[英]How to specialise the return type of a function with an enum in C++?
我正在使用變量為C ++中的語法分析器存儲一系列類型。 語法規則的每個組成部分都有一個類別(類型為枚舉)和一個值。 組成部分根據類別存儲一種類型的值。 為了示例,我將類別簡化為'String'=>存儲字符串,'Number'=>存儲int。
我想根據類別枚舉獲得具有正確類型的成分的值。 我怎樣才能做到這一點?
我在下面編寫了示例代碼,在其中我構造了兩個組成部分:strCon,存儲字符串和intCon,存儲int,並嘗試獲取它們的值。
我想將strCon中的字符串分配給strVal,將intCon中的int分配給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++.
}
您可以通過創建中間特征類來實現一個間接級別:
enum E
{
X,
Y
};
template <E e>
struct Traits;
template <>
struct Traits<X>
{
using type = std::string;
};
template <>
struct Traits<Y>
{
using type = int;
};
template <E e>
typename Traits<e>::type get();
template <>
typename Traits<X>::type get<X>()
{
return "";
}
template <>
// actually, using the appropriate type directly works as well...
int get<Y>()
{
return 7;
}
你現在可以調用這樣的函數:
std::string s = get<X>();
int n = get<Y>();
您需要添加一些特性來提供枚舉類型,例如重用OfCategory
:
template<Category T> struct OfCategory;
template<> struct OfCategory<Category::String> { using type = std::string; };
template<> struct OfCategory<Category::Number> { using type = int; };
然后,無需額外的專業化:
template <Category T>
const typename OfCategory<T>::type&
getValue(OfCategory<T> type, Constituent const& constituent)
{
// Uses the variant's get function.
return std::get<typename OfCategory<T>::type>(constituent.val);
}
用於調用: getValue(OfCategory<Category::String>{}, strCon)
。
甚至:
template <Category T>
const typename OfCategory<T>::type&
getValue(Constituent const& constituent)
{
// Uses the variant's get function.
return std::get<typename OfCategory<T>::type>(constituent.val);
}
用於調用getValue<Category::String>(strCon);
我懷疑這樣的事情會起作用:
template<Category T>
auto getValue(OfCategory<T> type, Constituent const& constituent)
-> decltype(std::get<T>(constituent.val))
{
return std::get<T>(constituent.val);
}
(可能需要將T
為size_t
)。 換句話說,你的getValue
是std::get
的重新發明
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.