我在C++中使用变体来存储语法解析器的一系列类型。每个语法规则的组成部分都有一个类别(类型为枚举)和一个值。该组成部分根据其类别存储一种类型的值。为了举例说明,我将类别简化为'String' => 存储字符串,'Number' => 存储整数。
我想要根据其类别枚举获取组成部分的正确类型的值。我该怎么做?
我编写了下面的示例代码,其中构造了两个组成部分:strCon,存储一个字符串;intCon,存储一个整数,并尝试获取它们的值。
我想将strCon中的字符串赋值给strVal,将intCon中的整数赋值给intVal。
#include <variant>
struct Constituent
{
enum class Category {String, Number};
using Value = std::variant<std::string, int>;
Category cat;
Value val;
// Using a struct ideally to allow partial specialisation of the template,
// so I can pass the enum without the return type.
template<Category T>
struct OfCategory {};
template<Category T, typename U>
friend U const& getValue(OfCategory<T>, Constituent const&);
}
using Category = Constituent::Category;
// Template to return the value as the correct type
// for the constituent's category.
template<Category T, typename U>
U const& getValue(OfCategory<T> type, Constituent const& constituent)
{
// Uses the variant's get function.
return std::get<U>(constituent.val);
}
// Specialisation to return string from Category::String.
template<>
string const& getValue(OfCategory<Category::String> type,
Constituent const& constituent)
{
return getValue<Category::String, string>(constituent);
}
// Specialisation to return int from Category::Number.
template<>
int const& getValue(OfCategory<Category::Number> type,
Constituent const& constituent)
{
return getValue<Category::Number, int>(constituent);
}
int main()
{
Constituent strCon = {Category::String, "This is a string!"};
Constituent intCon = {Category::Number, 20};
// In my current implementation, I want this to work with
// the type wrapper as an overload for the function.
string strVal = getValue(OfCategory<Category::String>{}, strCon);
int intVal = getValue(OfCategory<Category::Number>{}, intCon);
// But it would be better to directly use the template.
strVal = getValue<Category::String>(strCon);
intVal = getValue<Category::Number>(intCon);
// The only way I can get it to work, is to explicitly provide
// the return type, which defeats the point.
strVal = getValue<Category::String, string>(
OfCategory<Category::String>{}, strCon);
intVal = getValue<Category::Number, int>(
OfCategory<Category::Number>{}, intCon);
// Ideally, I could use the cat parameter in Constituent to dynamically
// infer the return type, but I don't believe something like this is
// possible in C++.
}
cat
。val.index()
提供了等效的信息。而且你的getValues
似乎在重新发明std::get
。 - Igor Tandetnikstd::variant
可以有重复的类型;std::variant<int, int>
是有效的。std::get
可以接受一个整数索引。 - Igor Tandetnik