简体   繁体   English

使用强类型枚举的值作为 boost::mpl::map 中的索引

[英]Use the value of strongly typed enum as index in boost::mpl::map

I am using a C++ map structure defined similar to std::map<Foo, std::any> for storing attributes of a compiler symbol table.我正在使用定义类似于std::map<Foo, std::any>的 C++ map 结构来存储编译器符号表的属性。 The Foo is a strongly typed enum, such as enum class Foo {ENUM} . Foo是强类型枚举,例如enum class Foo {ENUM} After casting some other types to std::any , I need std::any_cast to cast it back if I access the entry by the Foo::ENUM key.在将一些其他类型转换为std::any之后,如果我通过Foo::ENUM键访问条目,我需要std::any_cast将其转换回来。 The type parameter of std::any_cast is tied to Foo::ENUM . std::any_cast的类型参数与Foo::ENUM相关联。

That being said, I want something for automatically determining the type parameter for std::any_cast based on Foo::ENUM as following:话虽这么说,我想要一些东西来自动确定基于Foo::ENUMstd::any_cast的类型参数,如下所示:

std::map<Foo, std::any> m;
const auto x = std::any_cast<some_magic(Foo::ENUM)::type>(m[Foo::ENUM]);

Here is my current implementation:这是我当前的实现:

#include <iostream>
#include <string>
#include <vector>
#include <type_traits>
#include <any>
#include <map>

#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x ## y

#define ENABLE_ENUM_TO_TYPE(enum_class_name) \
template <enum_class_name> struct CAT(enum_class_name, _enum_to_type);

#define ENUM_TYPE_PAIR(enum_class_name, enum_key, type_) \
template <> struct CAT(enum_class_name, _enum_to_type)<enum_class_name::enum_key> {using type = type_;};

enum class Foo {
  A1, A2
};

enum class Bar {
  B1, B2, B3
};

ENABLE_ENUM_TO_TYPE(Foo);
ENABLE_ENUM_TO_TYPE(Bar);
ENUM_TYPE_PAIR(Foo, A1, int);
ENUM_TYPE_PAIR(Foo, A2, double);
ENUM_TYPE_PAIR(Bar, B1, std::string);
ENUM_TYPE_PAIR(Bar, B2, std::vector<int>);

template <auto T1>
constexpr auto enum_to_type_impl() {
#define COMPARE_ENUM_CLASS(enum_class_name) \
if constexpr (std::is_same_v<decltype(T1), enum_class_name>) { return CAT(enum_class_name, _enum_to_type)<T1>{};} else
  COMPARE_ENUM_CLASS(Foo)
  COMPARE_ENUM_CLASS(Bar)
#undef COMPARE_ENUM_CLASS
{}
}

template <auto EnumVal>
struct enum_to_type {
  using type = typename decltype(enum_to_type_impl<EnumVal>())::type;
};

int main() {
  std::map<Bar, std::any> m;
  m[Bar::B1] = std::string{"Hello"};
  std::cout << std::any_cast<enum_to_type<Bar::B1>::type>(m[Bar::B1]) << std::endl;
  return 0;
}

However, my code above is still cumbersome.但是,我上面的代码仍然很麻烦。 I look into the boost mpl library but apparently it does not offer something like mpl::enum_ , and I have tried the following code but it does not work:我查看了 boost mpl 库,但显然它不提供类似mpl::enum_的东西,我尝试了以下代码,但它不起作用:

#include <boost/mpl/map.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/at.hpp>
#include <string>
#include <iostream>

enum class Bar {
  C1, C2
};

template <auto EnumVal> struct enum_
{
  using type = enum_;
  using value_type = decltype(EnumVal);
  typedef mpl_::integral_c_tag tag;
};


typedef boost::mpl::map<
  boost::mpl::pair<enum_<Bar::C1>, std::string>,
  boost::mpl::pair<enum_<Bar::C2>, int>
  > m;

int main() {
  boost::mpl::at<m, enum_<Bar::C1>>::type x;
  return 0;
}

When compiling the code above, I get the following error message:编译上面的代码时,出现以下错误消息:

main.cpp: In function ‘int main()’:
main.cpp:24:38: error: incomplete type ‘boost::mpl::at<boost::mpl::map<boost::mpl::pair<enum_<Bar::C1>, std::__cxx11::basic_string<char> >, boost::mpl::pair<enum_<Bar::C2>, int> >, enum_<Bar::C1> >’ used in nested name specifier
   24 |   boost::mpl::at<m, enum_<Bar::C1>>::type x;

Any ideas?有任何想法吗? Is the data type for boost::mpl::map extensible? boost::mpl::map的数据类型是否可扩展?

EDIT : I have added #include <boost/mpl/at.hpp> in the above code snipet following the accepted answer , and it works properly.编辑:我在上面的代码片段中添加了#include <boost/mpl/at.hpp>接受的答案之后,它工作正常。 As for the boost::mp11 solution, my code is on https://godbolt.org/z/KvjecnTe3 , but gcc fails to compile it, and I have submitted an issue on https://github.com/boostorg/mp11/issues/72 .至于boost::mp11的解决方案,我的代码在https://godbolt.org/z/KvjecnTe3 ,但是gcc编译失败,我在https上提交了issue://github.com/boostorg/mp11 /问题/72

You need to include #include <boost/mpl/at.hpp> .您需要包含#include <boost/mpl/at.hpp> Also, I wouldn't recommend using boost::mpl - it's really slow to compile.另外,我不推荐使用 boost::mpl - 它编译起来真的很慢。 Your "cumbersome" solution is fastest IMHO, and if you don't like it you might like to look towards boost::mp11 or any other "more modern" metaprogramming library.您的“笨重”解决方案是最快的恕我直言,如果您不喜欢它,您可能希望看看 boost::mp11 或任何其他“更现代”的元编程库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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