编译时结构的枚举映射

时间:2017-03-21 14:40:57

标签: c++ templates template-meta-programming

我试图根据一些枚举值创建(在编译时)结构体结构。我会编写代码,它更容易解释:

enum class EnumTest {A,B,C,D,E,F};

template<class EnumType, EnumType enumValue>
struct MappedStruct
  {
  int element = 0;
  };

template<class EnumType, EnumType enumValue>
struct VecStruct
  {
  std::vector<MappedStruct<EnumType, enumValue>> vec;
  };


template<class EnumType, EnumType... enumValues>
class MapperSelection
  {
  public:

    template<EnumType type>
    void insert(int arg) {mapper_<EnumType, type>.vec.push_back(arg); // * compilation error here *
 }

  private:
    VecStruct<EnumType, enumValues...> mapper_;
  };
int main()
{
MapperSelection< EnumTest::A, EnumTest::B, EnumTest::C> selection;
selection.insert<EnumTest::>(100);
return 0;
}

有没有办法编译这段代码?或一些解决方法具有相同的行为?可能与所有的枚举?

1 个答案:

答案 0 :(得分:1)

对我来说并不完全清楚,但我认为你想要的是这样的:

#include <vector>
#include <ostream>
#include <tuple>
#include <iostream>

struct A { static constexpr const char* name() { return "A"; }};
struct B { static constexpr const char* name() { return "B"; }};
struct C { static constexpr const char* name() { return "C"; }};

template<class Tag>
struct tagged_vector : std::vector<int>
{
    using std::vector<int>::vector;
};

template<class...Tags>
struct selection
{
    using storage_type = std::tuple<tagged_vector<Tags>...>;

    template<class Tag>
    void add(Tag, int value)
    {
        std::get<tagged_vector<Tag>>(storage_).push_back(value);
    }

    template<std::size_t I>
    static const char* make_sep(std::integral_constant<std::size_t, I>) {
        return "\n";
    }

    static const char* make_sep(std::integral_constant<std::size_t, 0>) {
        return "";
    };

    template<class Tag>
    static void impl_report(std::ostream& os, tagged_vector<Tag> const& vec, const char* sep)
    {
        os << sep << Tag::name() << " ";
        std::copy(std::begin(vec), std::end(vec), std::ostream_iterator<int>(os, ", "));
    }

    template<class Tuple, std::size_t...Is>
    static void impl_report(std::ostream& os, Tuple&& tup, std::index_sequence<Is...>)
    {
        using expand = int[];
        void(expand{0,
                    (impl_report(os, std::get<Is>(tup), make_sep(std::integral_constant<std::size_t, Is>())), 0)...
        });
    };

    std::ostream& report(std::ostream& os) const {

        impl_report(os, storage_, std::make_index_sequence<std::tuple_size<storage_type>::value>());
        return os;
    }


    storage_type storage_;
};

int main()
{

    auto sel = selection<A, B, C>();

    sel.add(A(), 100);
    sel.add(A(), 101);
    sel.add(B(), 90);
    sel.add(C(), 10);
    sel.add(C(), 11);

    sel.report(std::cout) << std::endl;
}

预期产出:

A 100, 101, 
B 90, 
C 10, 11, 

标签是类型还是枚举(可能)并不重要,但如果您可以使用它们,类型将使生活更轻松。

<强>更新

用枚举重新实现。请注意,它不够整洁,需要更多关于用户的知识。在c ++设计中,这通常被视为一件坏事

#include <vector>
#include <ostream>
#include <tuple>
#include <iostream>

enum class my_tag
{
 A,B,C
};

const char* name(my_tag t)
{
    switch(t) {
        case my_tag ::A:
            return "A";
        case my_tag ::B:
            return "B";
        case my_tag ::C:
            return "C";
    }
    return "logic error";
}

template<class TagType, TagType TagValue>
struct tagged_vector : std::vector<int>
{
    using std::vector<int>::vector;
};

template<class TagType, TagType...Tags>
struct selection
{
    using storage_type = std::tuple<tagged_vector<TagType, Tags>...>;

    template<TagType Tag>
    void add(int value)
    {
        std::get<tagged_vector<TagType, Tag>>(storage_).push_back(value);
    }

    template<std::size_t I>
    static const char* make_sep(std::integral_constant<std::size_t, I>) {
        return "\n";
    }

    static const char* make_sep(std::integral_constant<std::size_t, 0>) {
        return "";
    };

    template<TagType Tag>
    static void impl_report(std::ostream& os, tagged_vector<TagType, Tag> const& vec, const char* sep)
    {
        os << sep << name(Tag) << " ";
        std::copy(std::begin(vec), std::end(vec), std::ostream_iterator<int>(os, ", "));
    }

    template<class Tuple, std::size_t...Is>
    static void impl_report(std::ostream& os, Tuple&& tup, std::index_sequence<Is...>)
    {
        using expand = int[];
        void(expand{0,
                    (impl_report(os, std::get<Is>(tup), make_sep(std::integral_constant<std::size_t, Is>())), 0)...
        });
    };

    std::ostream& report(std::ostream& os) const {

        impl_report(os, storage_, std::make_index_sequence<std::tuple_size<storage_type>::value>());
        return os;
    }


    storage_type storage_;
};

int main()
{

    auto sel = selection<my_tag, my_tag::A, my_tag::B, my_tag::C>();

    sel.add<my_tag::A>(100);
    sel.add<my_tag::A>(101);
    sel.add<my_tag::B>(90);
    sel.add<my_tag ::C>(10);
    sel.add<my_tag ::C>(11);

    sel.report(std::cout) << std::endl;

}

更新了c ++ 11 ghastliness

#include <vector>
#include <ostream>
#include <tuple>
#include <iostream>

namespace notstd  // WARNING: at own risk, otherwise use own namespace
{
    template <size_t... Ints>
    struct index_sequence
    {
        using type = index_sequence;
        using value_type = size_t;
        static constexpr std::size_t size() noexcept { return sizeof...(Ints); }
    };

    // --------------------------------------------------------------

    template <class Sequence1, class Sequence2>
    struct _merge_and_renumber;

    template <size_t... I1, size_t... I2>
    struct _merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
        : index_sequence<I1..., (sizeof...(I1)+I2)...>
    { };

    // --------------------------------------------------------------

    template <size_t N>
    struct make_index_sequence
        : _merge_and_renumber<typename make_index_sequence<N/2>::type,
                              typename make_index_sequence<N - N/2>::type>
    { };

    template<> struct make_index_sequence<0> : index_sequence<> { };
    template<> struct make_index_sequence<1> : index_sequence<0> { };

    template <class T, class Tuple>
    struct Index;

    template <class T, class... Types>
    struct Index<T, std::tuple<T, Types...>> {
        static const std::size_t value = 0;
    };

    template <class T, class U, class... Types>
    struct Index<T, std::tuple<U, Types...>> {
        static const std::size_t value = 1 + Index<T, std::tuple<Types...>>::value;
    };
}

enum class my_tag
{
 A,B,C
};

const char* name(my_tag t)
{
    switch(t) {
        case my_tag ::A:
            return "A";
        case my_tag ::B:
            return "B";
        case my_tag ::C:
            return "C";
    }
    return "logic error";
}

template<class TagType, TagType TagValue>
struct tagged_vector : std::vector<int>
{
    using std::vector<int>::vector;
};

template<class TagType, TagType...Tags>
struct selection
{
    using storage_type = std::tuple<tagged_vector<TagType, Tags>...>;

    template<TagType Tag>
    void add(int value)
    {
        using index = notstd::Index<tagged_vector<TagType, Tag>, storage_type>;
        std::get<index::value>(storage_).push_back(value);
    }

    template<std::size_t I>
    static const char* make_sep(std::integral_constant<std::size_t, I>) {
        return "\n";
    }

    static const char* make_sep(std::integral_constant<std::size_t, 0>) {
        return "";
    };

    template<TagType Tag>
    static void impl_report(std::ostream& os, tagged_vector<TagType, Tag> const& vec, const char* sep)
    {
        os << sep << name(Tag) << " ";
        std::copy(std::begin(vec), std::end(vec), std::ostream_iterator<int>(os, ", "));
    }

    template<class Tuple, std::size_t...Is>
    static void impl_report(std::ostream& os, Tuple&& tup, notstd::index_sequence<Is...>)
    {
        using expand = int[];
        void(expand{0,
                    (impl_report(os, std::get<Is>(tup), make_sep(std::integral_constant<std::size_t, Is>())), 0)...
        });
    };

    std::ostream& report(std::ostream& os) const {

        impl_report(os, storage_, notstd::make_index_sequence<std::tuple_size<storage_type>::value>());
        return os;
    }


    storage_type storage_;
};

int main()
{

    auto sel = selection<my_tag, my_tag::A, my_tag::B, my_tag::C>();

    sel.add<my_tag::A>(100);
    sel.add<my_tag::A>(101);
    sel.add<my_tag::B>(90);
    sel.add<my_tag ::C>(10);
    sel.add<my_tag ::C>(11);

    sel.report(std::cout) << std::endl;

}