简体   繁体   中英

Can I use BOOST_FUSION_ADAPT_STRUCT with inherited stuff?

Assume I have

struct cat
{
    int tail;
    int head;
};

struct bird
{
    int wing;
    int bursa;
};

If I do this...

struct wat : public cat, public bird
{

};

BOOST_FUSION_ADAPT_STRUCT(cat,tail,head)
BOOST_FUSION_ADAPT_STRUCT(bird, wing, bursa)
BOOST_FUSION_ADAPT_STRUCT(wat, wat::cat, wat::bird)

... I cannot get a build, but if I explicit refer to the inherited objects like what's below, it's perfectly valid.

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace qi = boost::spirit::qi;
struct wat
{
public:
    cat z;
    bird q;
};

BOOST_FUSION_ADAPT_STRUCT(cat,tail,head)
BOOST_FUSION_ADAPT_STRUCT(bird, wing, bursa)
BOOST_FUSION_ADAPT_STRUCT(wat, z, q)

Is there some way to make the first version work, such that I can adapt a struct of inhereted public members? I definitely do NOT want to do BOOST_FUSION_ADAPT_STRUCT(wat,tail,head,wing,bursa) but this seems to be the only way to get there with inherited members I can find.

Similar question here: c++/boost fusion handle parent class

Short question: no that's not a feature.

You can use aggregation instead of inheritance,

struct wat {
    cat _cat;
    bird _bird;
};

BOOST_FUSION_ADAPT_STRUCT(wat, _cat, _bird)

but you won't magically get a flattened sequence.

What you might want to do in your code that treats fusion sequences, is code the support for known base classes and handle them in addition to the adapted sequence members.

Demo With Aggregation

Live On Coliru

#include <boost/fusion/include/adapted.hpp>

struct cat {
    int tail;
    int head;
};

struct bird {
    int wing;
    int cloaca;
};

struct wat {
    cat _cat;
    bird _bird;
};

BOOST_FUSION_ADAPT_STRUCT(cat, tail, head)
BOOST_FUSION_ADAPT_STRUCT(bird, wing, cloaca)
BOOST_FUSION_ADAPT_STRUCT(wat, _cat, _bird)

#include <iostream>
#include <boost/fusion/include/at_c.hpp>

template <typename T, int N = 0> void print(T const& obj) {
    namespace fus = boost::fusion;
    if constexpr (fus::traits::is_sequence<T>::value) {
        if (N==0)
            std::cout << "{";

        if constexpr (N < fus::size(obj).value) {
            auto name = boost::fusion::extension::struct_member_name<T, N>::call();
            std::cout << ' ' << name << '=';
            print(fus::at_c<N>(obj));
            std::cout << ';';
            print<T, N+1>(obj);
        } else {
            std::cout << " }";
        }
    } else {
        std::cout << obj;
    }
}

int main() {
    print(wat { {1,2}, {3,4} });
}

Prints

{ _cat={ tail=1; head=2; }; _bird={ wing=3; cloaca=4; }; }

Demo With Hardcoded Lists Of Bases

Live On Coliru

#include <boost/fusion/include/adapted.hpp>

struct cat {
    int tail;
    int head;
};

struct bird {
    int wing;
    int cloaca;
};

struct wat : cat, bird {
    int something;
    int extra;

    wat(int tail, int head, int wing, int cloaca, int something, int extra)
        : cat{tail, head}, bird{wing, cloaca}, something(something), extra(extra)
    { }
};

BOOST_FUSION_ADAPT_STRUCT(cat, tail, head)
BOOST_FUSION_ADAPT_STRUCT(bird, wing, cloaca)
BOOST_FUSION_ADAPT_STRUCT(wat, something, extra)

#include <iostream>
#include <boost/fusion/include/at_c.hpp>

template <typename... KnownBases>
struct Demo {
    template <typename T, int N = 0> static void print(T const& obj, bool outer_sequence_braces = true) {
        namespace fus = boost::fusion;
        if constexpr (fus::traits::is_sequence<T>::value) {
            if (N==0)
            {
                if (outer_sequence_braces) std::cout << "{";
                print_bases<KnownBases...>(obj);
            }

            if constexpr (N < fus::size(obj).value) {
                auto name = boost::fusion::extension::struct_member_name<T, N>::call();
                std::cout << ' ' << name << '=';
                print(fus::at_c<N>(obj), true/*inner sequences get braces*/);
                std::cout << ';';
                print<T, N+1>(obj, outer_sequence_braces);
            } else {
                if (outer_sequence_braces) std::cout << " }";
            }
        } else {
            std::cout << obj;
        }
    }

    template <typename Base, typename T> static bool print_base(T const& obj) {
        if constexpr (not std::is_same<Base, T>() && std::is_base_of<Base, T>())
            print(static_cast<Base const&>(obj), false);
        return true;
    }

    template <typename... Bases, typename T> static void print_bases(T const& obj) {
        bool discard[] = { print_base<Bases>(obj)... };
        (void) discard;
    }
};

int main() {
    Demo<cat, bird>::print(wat { 1, 2, 3, 4, 5, 6 });
}

Prints

{ tail=1; head=2; wing=3; cloaca=4; something=5; extra=6; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM