我有一个变体ScalarVar
using ScalarVar = std::variant<int, std::string>;
还有一个变体Var
,它本身可以是ScalarVar
s的std::vector
或ScalarVar
using Var = std::variant<ScalarVar, std::vector<ScalarVar>>;
[我想制作一个函数template<typename T, typename Variant> T Get(const Variant& var);
,当给定不包含内部变体的变体时,其作用将与std::get<T>
相同,即,如果T
当前包含Variant
,它将返回T
的值,或者如果给定包含其他变体的变体,它将递归获取所包含的类型,直到找到非变体,然后返回该变体。
到目前为止,这是我迄今为止最好的尝试:
#include <iostream>
#include <variant>
#include <string>
#include <typeindex>
#include <vector>
#include <map>
template<typename T, typename... T2>
struct is_variant { static inline constexpr bool value = false; };
template<typename... T>
struct is_variant<std::variant<T...>> { static inline constexpr bool value = true; };
template<typename T, typename Variant>
T Get(const Variant& var) {
static_assert (is_variant<Variant>::value == true, "Template parameter Variant must be a std::variant");
auto inner = std::visit([](const auto& i){ return i; }, var);
if constexpr(is_variant<typeof(inner)>::value) {
return Get<T>(inner);
}
else return inner;
}
int main()
{
using ScalarVar = std::variant<int, std::string>;
using Var = std::variant<ScalarVar, std::vector<ScalarVar>>;
ScalarVar s = 5;
std::cout << Get<int>(s) << std::endl;
return 0;
}
如果T
不是T
,这应该简单地返回std::variant
,如果std::get<InnerT>
是包含类型T
的std :: variant,则返回T
。
但是我从gcc那里得到了一个非常复杂的编译错误:
std::cout << Get<int>(s) << std::endl
/usr/include/c++/9/variant:1005: error: invalid conversion from ‘std::__success_type<std::__cxx11::basic_string<char> >::type (*)(Get(const Variant&) [with T = int; Variant = std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >]::<lambda(const auto:22&)>&&, const std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&)’ {aka ‘std::__cxx11::basic_string<char> (*)(Get(const Variant&) [with T = int; Variant = std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >]::<lambda(const auto:22&)>&&, const std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&)’} to ‘int (*)(Get(const Variant&) [with T = int; Variant = std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >]::<lambda(const auto:22&)>&&, const std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&)’ [-fpermissive]
1005 | { return _Array_type{&__visit_invoke}; }
| ^
| |
| std::__success_type<std::__cxx11::basic_string<char> >::type (*)(Get(const Variant&) [with T = int; Variant = std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >]::<lambda(const auto:22&)>&&, const std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&) {aka std::__cxx11::basic_string<char> (*)(Get(const Variant&) [with T = int; Variant = std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >]::<lambda(const auto:22&)>&&, const std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&)}
如何获得所需的行为?
问题是此行:
[在调用T
时需要区分std::variant<...>
,std::visit
和其他所有内容。