バリアントを使用して、C ++の構文パーサーのさまざまな型を格納しています。構文ルールの各構成要素には、(列挙型の)カテゴリと値があります。構成要素は、カテゴリに応じて値のタイプを格納します。例として、カテゴリを「文字列」=>文字列を格納し、「数値」=>整数を格納するように簡略化しました。
カテゴリ列挙型に従って正しいタイプの構成要素の値を取得したいと思います。これどうやってするの?
以下にサンプルコードを記述しました。ここでは、文字列を格納するstrConとintを格納するintConの2つの構成要素を作成し、それらの値を取得しようとしています。
strConの文字列をstrValに割り当て、intを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++.
}
列挙型からタイプを提供するには、いくつかの特性を追加する必要があります。たとえば、次のように再利用し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);
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加