获取一个变量的值,它本身可能是另一个变量

问题描述 投票:1回答:2

我有一个变体ScalarVar

using ScalarVar = std::variant<int, std::string>;

还有一个变体Var,它本身可以是ScalarVar s的std::vectorScalarVar

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> > >&)}

如何获得所需的行为?

c++ c++17 template-meta-programming variant algebraic-data-types
2个回答
6
投票

问题是此行:


1
投票

[在调用T时需要区分std::variant<...>std::visit和其他所有内容。

© www.soinside.com 2019 - 2024. All rights reserved.