我试图弄清楚如何使用模板“magic”为元组中的每种类型自动生成 switch 语句。这是我的示例代码:
#include <string>
enum class AttributeID
{
ATTRIBUTE1,
ATTRIBUTE2,
ATTRIBUTE3
};
struct ATTRIBUTE1
{
static constexpr auto kID = AttributeID::ATTRIBUTE1;
using Value = unsigned int;
Value v;
};
struct ATTRIBUTE2
{
static constexpr auto kID = AttributeID::ATTRIBUTE2;
using Value = char;
Value v;
};
struct ATTRIBUTE3
{
static constexpr auto kID = AttributeID::ATTRIBUTE3;
using Value = std::string;
Value v;
};
class Attributes
{
public:
using ID = AttributeID;
template <typename T>
auto& get()
{
return std::get<T>(impl_).v;
}
private:
std::tuple<ATTRIBUTE1, ATTRIBUTE2, ATTRIBUTE3> impl_;
};
template <typename Attribute>
void foodleAttribute(Attribute& attr, unsigned int data)
{
//...
//This template will be specialized based upon the type of Attribute
}
void fiddleAttribute(Attributes& attrs, Attributes::ID id, unsigned int data)
{
switch(id)
{
case ATTRIBUTE1::kID:
foodleAttribute(attrs.get<ATTRIBUTE1>(), data);
break;
case ATTRIBUTE2::kID:
foodleAttribute(attrs.get<ATTRIBUTE2>(), data);
break;
case ATTRIBUTE3::kID:
foodleAttribute(attrs.get<ATTRIBUTE3>(), data);
break;
}
}
我想重写
fiddleAttribute
函数
template <typename Attributes>
void fiddleAttribute(Attributes& attrs, typename Attributes::ID id, unsigned int data)
{
//Generate a switch case (or equivalent) for each type (its kID constant) in the Attributes tuple
}
这样它会生成与我编写的显式 switch 语句等效的内容(打开
id
,调用模板化 foodleAttribute
函数)。
假设您的枚举类从 0 开始,您可以使用带有折叠表达式的
std::index_sequence
。
template <std::size_t... Is>
void fiddleAttributeImpl(Attributes& attrs, Attributes::ID id, unsigned int data, std::index_sequence<Is...>)
{
void(((static_cast<int>(id) == Is
&& (foodleAttribute(attrs.get<std::tuple_element_t<Is, Types>>(), data), false)) || ...));
}
void fiddleAttribute(Attributes& attrs, Attributes::ID id, unsigned int data)
{
return fiddleAttributeImpl(attrs, id, data, std::make_index_sequence<std::tuple_size_v<Types>>{});
}
要折叠的表达式是
static_cast<int>(id) == Is
&& (foodleAttribute(attrs.get<std::tuple_element_t<Is, Types>>(), data), true)
仅当运行时间
&&
等于索引id
时才会执行Is
之后的部分。逗号表达式使子表达式计算为 true 并短路以避免进一步比较。我们使用 std::tuple_element_t
从类型列表中获取第 Is
类型。
请参阅编译器资源管理器:https://godbolt.org/z/c1xfThz65
另外,一种本质上与 switch 语句更相似的方法是构建一个 lambda 数组,然后在运行时对其进行索引。
template <std::size_t... Is>
void fiddleAttributeImpl(Attributes& attrs, Attributes::ID id, unsigned int data, std::index_sequence<Is...>)
{
constexpr std::array<void(*)(Attributes&, unsigned int), std::tuple_size_v<Types>>
jumpTable{
[](Attributes& attrs, unsigned int data){foodleAttribute(attrs.get<std::tuple_element_t<Is, Types>>(), data);}
...
};
jumpTable[static_cast<int>(id)](attrs, data);
}
请参阅编译器资源管理器:https://godbolt.org/z/6jnGszvh3