C++ 结构的编译时枚举映射
我试图在编译时创建一个基于一些枚举值的结构。我将编写代码,更容易解释:C++ 结构的编译时枚举映射,c++,templates,template-meta-programming,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:
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;
}
有没有办法让你编译这段代码?或者一些解决方法来实现相同的行为?可能是所有的枚举?我不太清楚,但我想你想要的是这样的:
#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;
}
标记是类型还是枚举可能并不重要,但如果您可以使用类型,那么使用类型将使您的生活更轻松
更新:
使用枚举重新实现。请注意,它不太整洁,需要用户更多的知识。这在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可怕性更新:
假设VecStruct只接受一个枚举值,那么VecStruct映射器是什么;应该做什么?VecStruct是一种具有许多其他函数成员和特定于该枚举值的数据的结构。Mapper是一种具有其他更通用功能的管理器,例如,在所有内部结构中查找值。难道你不想要一个元组吗?@RichardHodges tuple是不够的,因为我想使用get而不是get非常有趣的解决方案!是的,我使用的是枚举,所以我必须稍微修改一下,使它能够与它们一起工作。性能如何?@user3770392编译时就解决了。当编译时打开优化功能,将不会有性能开销。这太棒了。。最后一个问题:在我的例子中,为枚举实现这一点,是否可以执行以下操作:使用storage_type=std::tuple
#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;
}
#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;
}