使用强类型枚举的值作为 boost::mpl::map 中的索引
我使用类似于 std::map
定义的 C++ 映射结构来存储编译器符号表的属性。 Foo
是一个强类型枚举,例如enum class Foo {ENUM}
。将一些其他类型转换为 std::any
后,如果我通过 Foo::ENUM< 访问条目,我需要
std::any_cast
将其转换回来/代码> 键。 std::any_cast
的类型参数与 Foo::ENUM
绑定。
话虽这么说,我想要基于 Foo::ENUM
自动确定 std::any_cast
的类型参数,如下所示:
std::map<Foo, std::any> m;
const auto x = std::any_cast<some_magic(Foo::ENUM)::type>(m[Foo::ENUM]);
这是我当前的实现:
#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;
}
但是,我的上面的代码还是很麻烦。我查看了 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;
}
编译上面的代码时,我得到以下内容错误消息:
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;
有什么想法吗? boost::mpl::map
的数据类型可扩展吗?
编辑: 我在上面的代码片段中添加了#include
,遵循接受的回答,并且工作正常。 至于 boost::mp11 解决方案,我的代码位于 https://godbolt.org/z/KvjecnTe3,但是 gcc 无法编译它,我已经在 https://github.com/boostorg/mp11/issues/72。
I am using a C++ map structure defined similar to std::map<Foo, std::any>
for storing attributes of a compiler symbol table. The Foo
is a strongly typed enum, such as 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. The type parameter of std::any_cast
is tied to Foo::ENUM
.
That being said, I want something for automatically determining the type parameter for std::any_cast
based on Foo::ENUM
as following:
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:
#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?
EDIT:
I have added #include <boost/mpl/at.hpp>
in the above code snipet following the accepted answer, and it works properly.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您需要包含
#include
。另外,我不建议使用 boost::mpl - 编译速度非常慢。恕我直言,您的“繁琐”解决方案是最快的,如果您不喜欢它,您可能希望寻求 boost::mp11 或任何其他“更现代”的元编程库。You need to include
#include <boost/mpl/at.hpp>
. Also, I wouldn't recommend using boost::mpl - it's really slow to compile. 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.