3

I'm having some trouble using karma to generate output for a struct that is held in a vector of boost::shared_ptrs. I've got a small test case using ints that doesn't compile. I was thinking I could use the deref_iterator customization point to handle this case or that perhaps that out-of-the-box spirit would notice that my container held a pointer type and do the extra dereference. Anyway here's the test case:

#include <boost/spirit/include/karma.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>

typedef boost::shared_ptr< int > ptr;
typedef std::vector< ptr > vec;

namespace boost {
namespace spirit {
namespace traits {

// specialise how iterators into containers of pointers are dereferenced
template <>
struct deref_iterator< typename container_iterator< vec const >::type >
{
    typedef int type;

    static
    type
    call( typename container_iterator< vec const >::type & it ) {
        return **it;
    }
};

} // namespace traits
} // namespace spirit
} // namespace boost



int
main() {
    vec v;
    v.push_back( ptr( new int( 1 ) ) );
    v.push_back( ptr( new int( 2 ) ) );
    v.push_back( ptr( new int( 3 ) ) );

    using namespace boost::spirit::karma;
    using boost::spirit::ascii::space;

    generate_delimited(
        std::ostream_iterator< char >( std::cout ),
        *int_,
        space,
        v
    );

    return 0;
}

and here are the compile errors:

...patience...
...patience...
...found 1986 targets...
...updating 3 targets...
gcc.compile.c++ /home/john/Dev/Bio/bin/Bio/gcc-4.6/release/src/spirit/vector-of-ptrs.o
In file included from /home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/numeric/bool_policies.hpp:16:0,
from /home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/numeric/bool.hpp:29,
from /home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/numeric.hpp:13,
from /home/john/src/boost/boost_1_51_0/boost/spirit/home/karma.hpp:15,
from /home/john/src/boost/boost_1_51_0/boost/spirit/include/karma.hpp:16,
from src/spirit/vector-of-ptrs.cpp:1:
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/numeric/detail/numeric_utils.hpp: In static member function ‘static boost::shared_ptr<
        int> boost::spirit::traits::absolute_value<boost::shared_ptr<int>, void>::call(boost::shared_ptr<int>)’:
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/numeric/detail/numeric_utils.hpp:149:41:   instantiated from ‘boost::spirit::traits::absolute_value<boost::shared_ptr<int> >::ame boost
    ::spirit::traits::absolute_value<T>::type = boost::shared_ptr<int> boost::spirit::traits::get_absolute_value(boost::shared_ptr<int>)’
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/numeric/int.hpp:213:57:   instantiated from ‘static bool boost::spirit::karma::any_int_generator<
        int, boost::spirit::unused_type, boost::spirit::unused_type, 10u, false
    >::insert_int(boost::spirit::karma::detail::output_iterator<ostream_iterator<char>, mpl_::int_<0>, boost::spirit::unused_type> &, const boost::shared_ptr<int> &)’
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/numeric/int.hpp:242:39:   instantiated from ‘static bool boost::spirit::karma::any_int_generator<
        int, boost::spirit::unused_type, boost::spirit::unused_type, 10u, false
    >::generate(
        boost::spirit::karma::detail::output_iterator<ostream_iterator<char>, mpl_::int_<0>, boost::spirit::unused_type> &, boost::spirit::context<
            boost::fusion::cons<const vector<boost::shared_ptr<int> > &, boost::fusion::nil>, boost::spirit::locals<> > &, const boost::spirit::karma::any_space<boost::spirit::char_encoding::ascii> &
      , const boost::shared_ptr<int> &)’
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/detail/fail_function.hpp:36:62:   instantiated from ‘bool boost::spirit::karma::detail::fail_function<
        boost::spirit::karma::detail::output_iterator<ostream_iterator<char>, mpl_::int_<0>, boost::spirit::unused_type>, boost::spirit::context<
            boost::fusion::cons<const vector<boost::shared_ptr<int> > &, boost::fusion::nil>, boost::spirit::locals<> >, boost::spirit::karma::any_space<boost::spirit::char_encoding::ascii> >
    ::operator()(const boost::spirit::karma::any_int_generator<int, boost::spirit::unused_type, boost::spirit::unused_type, 10u, false> &, const boost::shared_ptr<int> &) const’
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/detail/pass_container.hpp:274:13:   instantiated from ‘bool boost::spirit::karma::detail::pass_container<
        boost::spirit::karma::detail::fail_function<
            boost::spirit::karma::detail::output_iterator<ostream_iterator<char>, mpl_::int_<0>, boost::spirit::unused_type>, boost::spirit::context<
                boost::fusion::cons<const vector<boost::shared_ptr<int> > &, boost::fusion::nil>, boost::spirit::locals<> >, boost::spirit::karma::any_space<boost::spirit::char_encoding::ascii> >,
        vector<boost::shared_ptr<int> >, boost::spirit::karma::detail::indirect_iterator<vector<boost::shared_ptr<int> >::const_iterator>, mpl_::bool_<false> 
    >::dispatch_container(const boost::spirit::karma::any_int_generator<int, boost::spirit::unused_type, boost::spirit::unused_type, 10u, false> &, mpl_::mpl_::bool_<false>) const’
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/detail/pass_container.hpp:321:61:   [ skipping 2 instantiation contexts ]
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/operator/kleene.hpp:53:32:   instantiated from ‘bool boost::spirit::karma::base_kleene<
        boost::spirit::karma::any_int_generator<int, boost::spirit::unused_type, boost::spirit::unused_type, 10u, false>, mpl_::bool_<false>, boost::spirit::karma::kleene<
            boost::spirit::karma::any_int_generator<int, boost::spirit::unused_type, boost::spirit::unused_type, 10u, false> > 
    >::generate_subject(
        boost::spirit::karma::detail::pass_container<
            boost::spirit::karma::detail::fail_function<
                boost::spirit::karma::detail::output_iterator<ostream_iterator<char>, mpl_::int_<0>, boost::spirit::unused_type>, boost::spirit::context<
                    boost::fusion::cons<const vector<boost::shared_ptr<int> > &, boost::fusion::nil>, boost::spirit::locals<> >, boost::spirit::karma::any_space<boost::spirit::char_encoding::ascii> >
          , vector<boost::shared_ptr<int> >, boost::spirit::karma::detail::indirect_iterator<vector<boost::shared_ptr<int> >::const_iterator>, mpl_::bool_<false> >, const vector<
            boost::shared_ptr<int> > &, mpl_::mpl_::bool_<false>) const’
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/operator/kleene.hpp:126:17:   instantiated from ‘bool boost::spirit::karma::base_kleene<
        boost::spirit::karma::any_int_generator<int, boost::spirit::unused_type, boost::spirit::unused_type, 10u, false>, mpl_::bool_<false>, boost::spirit::karma::kleene<
            boost::spirit::karma::any_int_generator<int, boost::spirit::unused_type, boost::spirit::unused_type, 10u, false> > 
    >::generate(
        boost::spirit::karma::detail::output_iterator<ostream_iterator<char>, mpl_::int_<0>, boost::spirit::unused_type> &, boost::spirit::context<
            boost::fusion::cons<const vector<boost::shared_ptr<int> > &, boost::fusion::nil>, boost::spirit::locals<> > &, const boost::spirit::karma::any_space<boost::spirit::char_encoding::ascii> &
      , const vector<boost::shared_ptr<int> > &) const’
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/generate.hpp:161:53:   instantiated from ‘bool boost::spirit::karma::generate_delimited(
        boost::spirit::karma::detail::output_iterator<ostream_iterator<char>, mpl_::int_<0> > &, const boost::proto::exprns_::expr<
            boost::proto::tagns_::tag::dereference, boost::proto::argsns_::list1<const boost::spirit::terminal<boost::spirit::tag::int_> &>, 1l> &, const boost::proto::exprns_::expr<
            boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l> &, boost::spirit
        ::karma::delimit_flag::enum_type, const vector<boost::shared_ptr<int> > &)’
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/generate.hpp:185:82:   instantiated from ‘bool boost::spirit::karma::generate_delimited(
        ostream_iterator<char> &, const boost::proto::exprns_::expr<boost::proto::tagns_::tag::dereference, boost::proto::argsns_::list1<const boost::spirit::terminal<boost::spirit::tag::int_> &>,
            1l> &, const boost::proto::exprns_::expr<
            boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l> &, boost::spirit
        ::karma::delimit_flag::enum_type, const vector<boost::shared_ptr<int> > &)’
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/generate.hpp:227:48:   instantiated from ‘bool boost::spirit::karma::generate_delimited(
        const ostream_iterator<char> &, const boost::proto::exprns_::expr<
            boost::proto::tagns_::tag::dereference, boost::proto::argsns_::list1<const boost::spirit::terminal<boost::spirit::tag::int_> &>, 1l> &, const boost::proto::exprns_::expr<
            boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l> &, const vector<
            boost::shared_ptr<int> > &)’
src/spirit/vector-of-ptrs.cpp:46:2:   instantiated from here
/home/john/src/boost/boost_1_51_0/boost/spirit/home/karma/numeric/detail/numeric_utils.hpp:60:26: error: No match for ‘fabs(boost::shared_ptr<int> &)’

STL Decryptor reminder:
    Use the /cand:L option to see all suppressed template candidates

    "/home/john/src/stlfilt/gfilt"  -ftemplate-depth-128 -Wno-deprecated -Wno-unused -Wno-error -O3 -finline-functions -Wno-inline -Wall -fPIC -Wno-deprecated -Wno-unused -DBOOST_FILESYSTEM_VERSION=3 -DNDEBUG -DWITH_NONAMESPACES -DXML_LIBRARY  -I"../Bio" -I"../Hmm" -I"/home/john/src/boost/boost_1_51_0" -c -o "/home/john/Dev/Bio/bin/Bio/gcc-4.6/release/src/spirit/vector-of-ptrs.o" "src/spirit/vector-of-ptrs.cpp"

...failed gcc.compile.c++ /home/john/Dev/Bio/bin/Bio/gcc-4.6/release/src/spirit/vector-of-ptrs.o...
...removing /home/john/Dev/Bio/bin/Bio/gcc-4.6/release/src/spirit/vector-of-ptrs.o
...skipped <p/home/john/Dev/Bio/bin/Bio/gcc-4.6/release>spirit-vector-of-ptrs for lack of <p/home/john/Dev/Bio/bin/Bio/gcc-4.6/release>src/spirit/vector-of-ptrs.o...
...failed updating 1 target...
...skipped 1 target...
ildjarn
  • 62,044
  • 9
  • 127
  • 211
Epimetheus
  • 1,119
  • 1
  • 10
  • 19

1 Answers1

6

A bit of experimentation lead me to the reason why the specialization wasn't instantiatied, where expected: the iterator has become wrapped (with karma::detail::indirect_iterator) somewhere during the evalation of the generator expression.

Here is the fix that works for me:

namespace boost {
namespace spirit {
namespace traits {

    // specialise how iterators into containers of pointers are dereferenced
    template <>
        struct deref_iterator< karma::detail::indirect_iterator<vec::const_iterator> >
    {
        typedef karma::detail::indirect_iterator<vec::const_iterator> It;
        typedef int type;

        static type call( It const & it ) {
            return **it;
        }
    };

} // namespace traits
} // namespace spirit
} // namespace boost
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks again. This works for me too. I always try to sort out these problems by reading the docs. AFAICS I could never find this answer in there. I'll spend more time with the super long compiler error messages in the future. It looks like the answer relies on some implementation details in the karma::detail namespace which might be fragile but hey it does work. – Epimetheus Sep 07 '12 at 07:41
  • I agree. I have considered posting a question about this surprising behaviour on the [spirit-general] mailing list. (It might be a documentation deficiency, or a regression through leaked implementation details). Perhaps you could find more motivation to check with the mailing list :) – sehe Sep 07 '12 at 09:05