4

The purpose of the following code is to display the contents of a structure. It is based on this answer.

#include <iostream>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/bind.hpp>

struct Node {
    int a = 4;
    double b = 2.2;
};

BOOST_FUSION_ADAPT_STRUCT(Node, b)

struct print_visitor {
    template <class Index, class C> void operator()(Index, C &c) {
        std::cout << boost::fusion::extension::struct_member_name<
                         C, Index::value>::call() << "="
                  << boost::fusion::at<Index>(c) << std::endl;
    }
};

template <class C> void print_fields(C &c) {
    typedef boost::mpl::range_c<
        int, 0, boost::fusion::result_of::size<C>::type::value> range;
    boost::mpl::for_each<range>(
        boost::bind<void>(print_visitor(), _1, boost::ref(c)));
}

int main() {
    Node n;
    print_fields(n);
}

The compiler (gcc version 4.8.2) complains:

invalid use of incomplete type ‘struct boost::fusion::result_of::at<Node, mpl_::integral_c<int, 0> >’ typedef typename T::type type;

What is the reason and how can I resolve this?

Here is the complete output of the compiler:

-*- mode: compilation; default-directory: "~/SearchLib/AstarWithPolicies/temp/" -*-
Compilation started at Thu Dec 10 11:54:27

make -k 
g++ -Wall -Wextra -Werror -std=c++11 -pedantic -I ~/boost_1_59_0 -I /usr/include/cairomm-1.0/ -I /usr/include/cairo/ -I /usr/include/sigc++-2.0/ -I /usr/lib/x86_64-linux-gnu/sigc++-2.0/include/ -I /usr/include/freetype2/ -g -c temp.cpp
In file included from /home/meir/boost_1_59_0/boost/utility/enable_if.hpp:15:0,
                 from /home/meir/boost_1_59_0/boost/fusion/support/tag_of.hpp:11,
                 from /home/meir/boost_1_59_0/boost/fusion/support/category_of.hpp:12,
                 from /home/meir/boost_1_59_0/boost/fusion/adapted/struct/detail/extension.hpp:14,
                 from /home/meir/boost_1_59_0/boost/fusion/adapted/struct/adapt_struct.hpp:27,
                 from temp.cpp:7:
/home/meir/boost_1_59_0/boost/core/enable_if.hpp: In instantiation of ‘struct boost::lazy_disable_if_c<false, boost::fusion::result_of::at<Node, mpl_::integral_c<int, 0> > >’:
/home/meir/boost_1_59_0/boost/core/enable_if.hpp:70:10:   required from ‘struct boost::lazy_disable_if<boost::is_const<Node>, boost::fusion::result_of::at<Node, mpl_::integral_c<int, 0> > >’
/home/meir/boost_1_59_0/boost/fusion/sequence/intrinsic_fwd.hpp:102:5:   required by substitution of ‘template<class N, class Sequence> constexpr typename boost::lazy_disable_if<boost::is_const<Sequence>, boost::fusion::result_of::at<Sequence, N> >::type boost::fusion::at(Sequence&) [with N = mpl_::integral_c<int, 0>; Sequence = Node]’
temp.cpp:26:48:   required from ‘void print_visitor::operator()(Index, C&) [with Index = mpl_::integral_c<int, 0>; C = Node]’
/home/meir/boost_1_59_0/boost/bind/bind.hpp:315:34:   required from ‘void boost::_bi::list2<A1, A2>::operator()(boost::_bi::type<void>, F&, A&, int) [with F = print_visitor; A = boost::_bi::list1<mpl_::integral_c<int, 0>&>; A1 = boost::arg<1>; A2 = boost::reference_wrapper<Node>]’
/home/meir/boost_1_59_0/boost/bind/bind.hpp:907:50:   required from ‘boost::_bi::bind_t<R, F, L>::result_type boost::_bi::bind_t<R, F, L>::operator()(A1&&) [with A1 = mpl_::integral_c<int, 0>&; R = void; F = print_visitor; L = boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> >; boost::_bi::bind_t<R, F, L>::result_type = void]’
/home/meir/boost_1_59_0/boost/mpl/for_each.hpp:78:25:   required from ‘static void boost::mpl::aux::for_each_impl<false>::execute(Iterator*, LastIterator*, TransformFunc*, F) [with Iterator = boost::mpl::r_iter<mpl_::integral_c<int, 0> >; LastIterator = boost::mpl::r_iter<mpl_::integral_c<int, 1> >; TransformFunc = boost::mpl::identity<mpl_::na>; F = boost::_bi::bind_t<void, print_visitor, boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> > >]’
/home/meir/boost_1_59_0/boost/mpl/for_each.hpp:105:97:   required from ‘void boost::mpl::for_each(F, Sequence*, TransformOp*) [with Sequence = boost::mpl::range_c<int, 0, 1>; TransformOp = boost::mpl::identity<mpl_::na>; F = boost::_bi::bind_t<void, print_visitor, boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> > >]’
/home/meir/boost_1_59_0/boost/mpl/for_each.hpp:118:48:   required from ‘void boost::mpl::for_each(F, Sequence*) [with Sequence = boost::mpl::range_c<int, 0, 1>; F = boost::_bi::bind_t<void, print_visitor, boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> > >]’
temp.cpp:34:62:   required from ‘void print_fields(C&) [with C = Node]’
temp.cpp:39:19:   required from here
/home/meir/boost_1_59_0/boost/core/enable_if.hpp:63:30: error: invalid use of incomplete type ‘struct boost::fusion::result_of::at<Node, mpl_::integral_c<int, 0> >’
     typedef typename T::type type;
                              ^
In file included from /home/meir/boost_1_59_0/boost/fusion/sequence/intrinsic/begin.hpp:14:0,
                 from /home/meir/boost_1_59_0/boost/fusion/algorithm/iteration/detail/for_each.hpp:11,
                 from /home/meir/boost_1_59_0/boost/fusion/algorithm/iteration/for_each.hpp:12,
                 from /home/meir/boost_1_59_0/boost/fusion/include/for_each.hpp:11,
                 from temp.cpp:9:
/home/meir/boost_1_59_0/boost/fusion/sequence/intrinsic_fwd.hpp:53:16: error: declaration of ‘struct boost::fusion::result_of::at<Node, mpl_::integral_c<int, 0> >’
         struct at;
                ^
temp.cpp: In instantiation of ‘void print_visitor::operator()(Index, C&) [with Index = mpl_::integral_c<int, 0>; C = Node]’:
/home/meir/boost_1_59_0/boost/bind/bind.hpp:315:34:   required from ‘void boost::_bi::list2<A1, A2>::operator()(boost::_bi::type<void>, F&, A&, int) [with F = print_visitor; A = boost::_bi::list1<mpl_::integral_c<int, 0>&>; A1 = boost::arg<1>; A2 = boost::reference_wrapper<Node>]’
/home/meir/boost_1_59_0/boost/bind/bind.hpp:907:50:   required from ‘boost::_bi::bind_t<R, F, L>::result_type boost::_bi::bind_t<R, F, L>::operator()(A1&&) [with A1 = mpl_::integral_c<int, 0>&; R = void; F = print_visitor; L = boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> >; boost::_bi::bind_t<R, F, L>::result_type = void]’
/home/meir/boost_1_59_0/boost/mpl/for_each.hpp:78:25:   required from ‘static void boost::mpl::aux::for_each_impl<false>::execute(Iterator*, LastIterator*, TransformFunc*, F) [with Iterator = boost::mpl::r_iter<mpl_::integral_c<int, 0> >; LastIterator = boost::mpl::r_iter<mpl_::integral_c<int, 1> >; TransformFunc = boost::mpl::identity<mpl_::na>; F = boost::_bi::bind_t<void, print_visitor, boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> > >]’
/home/meir/boost_1_59_0/boost/mpl/for_each.hpp:105:97:   required from ‘void boost::mpl::for_each(F, Sequence*, TransformOp*) [with Sequence = boost::mpl::range_c<int, 0, 1>; TransformOp = boost::mpl::identity<mpl_::na>; F = boost::_bi::bind_t<void, print_visitor, boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> > >]’
/home/meir/boost_1_59_0/boost/mpl/for_each.hpp:118:48:   required from ‘void boost::mpl::for_each(F, Sequence*) [with Sequence = boost::mpl::range_c<int, 0, 1>; F = boost::_bi::bind_t<void, print_visitor, boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> > >]’
temp.cpp:34:62:   required from ‘void print_fields(C&) [with C = Node]’
temp.cpp:39:19:   required from here
temp.cpp:26:48: error: no matching function for call to ‘at(Node&)’
                   << boost::fusion::at<Index>(c) << std::endl;
                                                ^
temp.cpp:26:48: note: candidates are:
In file included from /home/meir/boost_1_59_0/boost/fusion/sequence/intrinsic/begin.hpp:14:0,
                 from /home/meir/boost_1_59_0/boost/fusion/algorithm/iteration/detail/for_each.hpp:11,
                 from /home/meir/boost_1_59_0/boost/fusion/algorithm/iteration/for_each.hpp:12,
                 from /home/meir/boost_1_59_0/boost/fusion/include/for_each.hpp:11,
                 from temp.cpp:9:
/home/meir/boost_1_59_0/boost/fusion/sequence/intrinsic_fwd.hpp:102:5: note: template<class N, class Sequence> constexpr typename boost::lazy_disable_if<boost::is_const<Sequence>, boost::fusion::result_of::at<Sequence, N> >::type boost::fusion::at(Sequence&)
     at(Sequence& seq);
     ^
/home/meir/boost_1_59_0/boost/fusion/sequence/intrinsic_fwd.hpp:102:5: note:   substitution of deduced template arguments resulted in errors seen above
/home/meir/boost_1_59_0/boost/fusion/sequence/intrinsic_fwd.hpp:107:5: note: template<class N, class Sequence> constexpr typename boost::fusion::result_of::at<const Sequence, N>::type boost::fusion::at(const Sequence&)
     at(Sequence const& seq);
     ^
/home/meir/boost_1_59_0/boost/fusion/sequence/intrinsic_fwd.hpp:107:5: note:   template argument deduction/substitution failed:
/home/meir/boost_1_59_0/boost/fusion/sequence/intrinsic_fwd.hpp: In substitution of ‘template<class N, class Sequence> constexpr typename boost::fusion::result_of::at<const Sequence, N>::type boost::fusion::at(const Sequence&) [with N = mpl_::integral_c<int, 0>; Sequence = Node]’:
temp.cpp:26:48:   required from ‘void print_visitor::operator()(Index, C&) [with Index = mpl_::integral_c<int, 0>; C = Node]’
/home/meir/boost_1_59_0/boost/bind/bind.hpp:315:34:   required from ‘void boost::_bi::list2<A1, A2>::operator()(boost::_bi::type<void>, F&, A&, int) [with F = print_visitor; A = boost::_bi::list1<mpl_::integral_c<int, 0>&>; A1 = boost::arg<1>; A2 = boost::reference_wrapper<Node>]’
/home/meir/boost_1_59_0/boost/bind/bind.hpp:907:50:   required from ‘boost::_bi::bind_t<R, F, L>::result_type boost::_bi::bind_t<R, F, L>::operator()(A1&&) [with A1 = mpl_::integral_c<int, 0>&; R = void; F = print_visitor; L = boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> >; boost::_bi::bind_t<R, F, L>::result_type = void]’
/home/meir/boost_1_59_0/boost/mpl/for_each.hpp:78:25:   required from ‘static void boost::mpl::aux::for_each_impl<false>::execute(Iterator*, LastIterator*, TransformFunc*, F) [with Iterator = boost::mpl::r_iter<mpl_::integral_c<int, 0> >; LastIterator = boost::mpl::r_iter<mpl_::integral_c<int, 1> >; TransformFunc = boost::mpl::identity<mpl_::na>; F = boost::_bi::bind_t<void, print_visitor, boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> > >]’
/home/meir/boost_1_59_0/boost/mpl/for_each.hpp:105:97:   required from ‘void boost::mpl::for_each(F, Sequence*, TransformOp*) [with Sequence = boost::mpl::range_c<int, 0, 1>; TransformOp = boost::mpl::identity<mpl_::na>; F = boost::_bi::bind_t<void, print_visitor, boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> > >]’
/home/meir/boost_1_59_0/boost/mpl/for_each.hpp:118:48:   required from ‘void boost::mpl::for_each(F, Sequence*) [with Sequence = boost::mpl::range_c<int, 0, 1>; F = boost::_bi::bind_t<void, print_visitor, boost::_bi::list2<boost::arg<1>, boost::reference_wrapper<Node> > >]’
temp.cpp:34:62:   required from ‘void print_fields(C&) [with C = Node]’
temp.cpp:39:19:   required from here
/home/meir/boost_1_59_0/boost/fusion/sequence/intrinsic_fwd.hpp:107:5: error: invalid use of incomplete type ‘struct boost::fusion::result_of::at<const Node, mpl_::integral_c<int, 0> >’
/home/meir/boost_1_59_0/boost/fusion/sequence/intrinsic_fwd.hpp:53:16: error: declaration of ‘struct boost::fusion::result_of::at<const Node, mpl_::integral_c<int, 0> >’
         struct at;
                ^
make: *** [all] Error 1

Compilation exited abnormally with code 2 at Thu Dec 10 11:54:27
Community
  • 1
  • 1
AlwaysLearning
  • 7,257
  • 4
  • 33
  • 68

1 Answers1

0

I found this post as I'm practicing the use of the MPL. I got here as I wanted to print the struct_member_name which you were successful at. The short answer is to include <boost/fusion/sequence.hpp>. fusion::at requires a sequence

BOOST_FUSION_ADAPT_STRUCT does only that, it does not create a sequence for the target. If you had have accessed the value in the same way you access the name, it would have worked.

boost::fusion::extension::access::struct_member<C, Index::value>::template apply<C>::call(x)

returns the value of interest. But of course, there is always a better way, that much code is pretty ugly. Once you have a sequence applied to your class, everything gets easier. Now, I didn't find a for_each that iterates and passes types, fusion::for_each dereferences the value and passes that to the functor. So I took some code from boost\fusion\sequence\io\out.hpp which moves across an iterator range.

This example prints the data your way, the iterator way, and directly using fusion's IO. I'm sure I'm missing a whole lot, but this is my first day of actually writing compile time code that works. Thanks for your question, I may not have gotten so far without it!

#include <iostream>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
//https://www.boost.org/doc/libs/1_78_0/libs/fusion/doc/html/fusion/support/deduce_sequence.html
#include <boost/bind/bind.hpp>
#include <boost/fusion/iterator/distance.hpp>
struct test {
    int val;
    std::string name;
};
BOOST_FUSION_ADAPT_STRUCT(test,val,name)

//the origanal with changes
struct print_class
{
    template <class Index, typename T>
    void operator()(Index, T& x) const
    {
        std::cout << "from print_class: " << boost::fusion::extension::struct_member_name<T, Index::value>::call()
            << " = " << boost::fusion::at<Index>(x) << std::endl;
    }
};

using namespace boost::placeholders;
template <class C> void print_fields(C& c) {

    typedef boost::mpl::range_c<
        int, 0, boost::fusion::result_of::size<C>::type::value> range;

    boost::mpl::for_each<range>(
        boost::bind<void>(print_class(), _1, boost::ref(c)));
}

//I could not find anything like this in the fusion namespace, so...
//T is a fusion iterator
namespace boost::fusion {
    template <typename T>
    auto get_name(){return  boost::fusion::extension::struct_member_name<T::seq_type, T::index::value>::call();
    }
}

//shamelessly stolen from fusion/io....
namespace {
    using namespace boost;
    namespace bf = fusion;
    struct print_sequence_loop
    {
        template <typename OS, typename First, typename Last>
        static void call(OS&, First&, Last&, mpl::true_)
        {
        }

        template <typename OS, typename First, typename Last>
        static void call(OS& os, First& first, Last& last, mpl::false_)
        {
            bf::result_of::equal_to<
                typename bf::result_of::next<First>::type
                , Last
            >is_last;

            //The code that prints
            os << bf::get_name<First>() << " = ";
            os << *first << std::endl;
            //End the code that prints

            call(os, fusion::next(first), last, is_last);
        }

        template <typename OS, typename First, typename Last>
        static void call(OS& os, First const& first, Last const& last)
        {
            bf::result_of::equal_to<First, Last> eq;
            call(os, first, last, eq);
        }
    };
    template <typename OS, typename Sequence>
    inline void print_sequence(OS& os, Sequence& seq)
    {
        print_sequence_loop::call(os, fusion::begin(seq), fusion::end(seq));
    }
}

using boost::fusion::operators::operator<<;

int main() {
    test the_test{ 12,"this is me" };
    print_sequence(std::cout, the_test);
    std::cout << '\n';
    print_fields(the_test);
    std::cout << "\n\n this is using fusions OS\n";
    std::cout << the_test << std::endl;
}

GCC demo And it works with MSVC.

lakeweb
  • 1,859
  • 2
  • 16
  • 21