在编译时从变体中获取类型
Posted
技术标签:
【中文标题】在编译时从变体中获取类型【英文标题】:Get type from variant at compile time 【发布时间】:2019-03-26 00:18:31 【问题描述】:我需要在编译时对变体类型是否可以保存类型进行类型检查。
我正在将枚举和字符串转换为变体,但我希望库与用户提供的变体兼容(对于它们支持的类型)。所以我有一个模板参数CustomVariant
来表示受支持类型子集AlphaBeta
、Gamma
、Delta
和Epsilon
的变体。如果我无法创建有效的变体,我想返回 std::nullopt
。
template <typename CustomVariant>
std::optional<CustomVariant> AsCustomVariant(LargeEnum type, const std::string& name)
case LargeEnum::ALPHA:
case LargeEnum::BETA:
return ConvertAlphaBeta(name);
case LargeEnum::GAMMA:
return ConvertGamma(name);
case LargeEnum::DELTA:
return ConvertDelta(name);
case LargeEnum::EPSILON:
return ConvertEpsilon(name);
default:
return std::nullopt;
我们的想法是使用某种模板魔法,它可以执行以下操作:
if (std::type_can_convert<CustomVariant, Gamma>)
return ConvertGamma(name);
else
return std::nullopt;
【问题讨论】:
什么是 CustomVariant?它是标准变体吗? Gamma 是一种类型吗?如果 tha 变体 hokds 一个可以转换的类型 - 从 ConvertGamma 的 reyurn 类型,那足够好,还是只有完全匹配?如果是第一个,什么样的排序?你的 switch 语句在哪里,它似乎丢失了。 LargeEnum 是连续的吗? 您正在寻找的模板魔法是if constexpr (std::is_convertible_v<Gamma, CustomVariant>)
。
【参考方案1】:
使用 c++17(我知道它是用 c++11 标记的),这非常容易 - 你甚至不必真正做任何事情:
#include <variant>
#include <type_traits>
#include <string>
using namespace std;
int main()
// this works, as expected
if constexpr(is_constructible_v<variant<int>, double>)
// this will run
// this is fine - it just won't happen,
if constexpr(is_constructible_v<variant<int>, string>)
// this won't run
else
// this will run
// but obviously the assignment of a string into that variant doesn't work...
variant<int> vi="asdf"s;
https://godbolt.org/z/I-wJU1
【讨论】:
【参考方案2】:首先我会这样做:
template<class T>struct tag_tusing type=T;;
template<class T>constexpr tag_t<T> tag;
template<class...Ts>using one_tag_of=std::variant<tag_t<Ts>...>;
using which_type=one_tag_of<AlphaBeta, Gamma, Delta /* etc */>;
which_type GetType(LargeEnum e)
switch (e)
case LargeEnum::Alpha:
case LargeEnum::Beta: return tag<AlphaBeta>;
// etc
现在我们这样做:
template <typename CustomVariant>
std::optional<CustomVariant> AsCustomVariant(LargeEnum type, const std::string& name)
auto which = GetType(type);
return std::visit( [&name](auto tag)->std::optional<CustomVariant>
using type=typename decltype(tag)::type;
if constexpr (std::is_convertible<CustomVariant, type>)
return MakeFromString( tag, name );
return std::nullopt;
, which );
这会留下MakeFromString
。
像这样编写重载:
inline Delta MakeFromString(tag_t<Delta>, std::string const& name) return ConvertDelta(name);
注意,不是专业。只是重载。
【讨论】:
以上是关于在编译时从变体中获取类型的主要内容,如果未能解决你的问题,请参考以下文章
尝试在 Linux Mint 17.1 64 位(未声明/非类型)上“制作”C++ 项目时从 cstdlib 编译错误和类似错误