我将从我想象如何使用我想创建的代码开始。它不必完全像这样,但它是我在标题中所说的“简洁”的一个很好的例子。就我而言,它是将类型映射到相关枚举值。
struct bar : foo<bar, foo_type::bar> { /* ... */ };
// \_/ \___________/
// ^ Type ^ Value
理想情况下,这应该是在 foo
的第一个模板参数之间自动注册双向映射。 ,一个类型,第二个,一个值,只有继承语法和正确的模板参数,以便我以后可以做下面例子中的内容。foo_type value = to_value<bar>; // Should be foo_type::bar
using type = to_type<foo_type::bar>; // Should be bar
我知道我可以为每个类型值对手动编写两个模板特化来做到这一点,但我想知道它是否会比不使用宏更乏味。我已经尝试过的是......
struct foo_base
{
template<typename T>
struct to_value
{};
template<foo_type E>
struct to_type
{};
};
template<typename T, foo_type E>
struct foo : public foo_base
{
template<>
struct to_value<T>
{
static constexpr auto value = E;
};
template<>
struct to_type<E>
{
using type = T;
};
};
然后它将与我在开始时介绍的内容类似地使用。foo_type value = foo_base::to_value<bar>::value; // Should be foo_type::bar
using type = foo_base::to_type<foo_type::bar>::type; // Should be bar
但它在 MSVC 上失败并出现以下错误。explicit specialization; 'foo_base::to_value' has already been instantiated
'foo_base::to_value': cannot specialize template in current scope
我觉得如果没有明确的手动特化,它可能无法实现,但是 C++17 允许许多令人惊讶的基于模板的 hack,所以在我放弃这个想法之前想与更有经验的人确认。
最佳答案
@HolyBlackCat 的回答太棒了。 Type-to-enum 可以通过比 ADL 黑客更简单的方式实现,所以我尝试将 enum-to-type 位提炼到最低限度:
template <auto E>
struct adl_to_type
{
friend auto foo_type_to_type(adl_to_type);
};
template<typename T, foo_type E>
struct foo
{
friend auto foo_type_to_type(adl_to_type<E>) { return (T*)nullptr; };
};
template <foo_type E>
using to_type = std::remove_pointer_t<decltype(foo_type_to_type(adl_to_type<E>{}))>;
int main()
{
to_type<foo_type::bar>{}.say();
return 0;
}
Run on gcc.godbolt.org
它仍然让我大吃一惊。
auto
返回类型在这里绝对是至关重要的。甚至将其更改为 T*
在 foo
会产生编译错误。我也尝试摆脱 adl_to_type
并使用 integral_constant
相反,但似乎声明 foo_type_to_type
因为用于解析 ADL 的类型中的 friend 函数是这里的关键。
关于c++ - 简明双向静态1 :1 mapping of values and types,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62448834/