为什么此get_index实现在VS2017上失败?

时间:2018-12-06 12:35:40

标签: c++ visual-studio visual-studio-2017 c++17 variant

Barry给了我们this gorgeous get_index for variants

template <typename> struct tag { };

template <typename T, typename V>
struct get_index;

template <typename T, typename... Ts> 
struct get_index<T, std::variant<Ts...>>
    : std::integral_constant<size_t, std::variant<tag<Ts>...>(tag<T>()).index()>
{ };

将按以下方式使用:

using V = variant<A, B, C>;
constexpr const size_t N = get_index<B, V>::value;  // 1

在Clang(OSX)中效果很好。

但是在Visual Studio 2017 I'm getting中,以下内容:

<source>(10): error C2039: 'index': is not a member of 'std::variant<tag<Ts>...>'
<source>(10): note: see declaration of 'std::variant<tag<Ts>...>'
<source>(11): note: see reference to class template instantiation 'get_index<T,std::variant<_Types...>>' being compiled
Compiler returned: 2

我不明白为什么。有什么想法吗?

(完整说明:在我的项目中,我实际上使用的是mpark::variant,因为我一直在使用没有std::variant的Xcode9。但是,您可以从Godbolt上看到上面的MCVE也会影响std::variant的实现。我相信问题可能出在上面的代码中,还是在编译器中。)

1 个答案:

答案 0 :(得分:2)

我打赌我的2美分是编译器错误。

我看到如果我写main()

std::cout << std::variant<tag<int>, tag<float>>{tag<float>{}}.index() << std::endl;

编译器没有抱怨。

如果我编写如下模板函数,也不要抱怨

template <typename T, typename ... Ts>
void foo ()
 { std::cout << std::variant<tag<Ts>...>(tag<T>{}).index() << std::endl; }

我从main()

来称呼它
foo<int, long, int, long long>();

main()中声明以下变量也没问题

std::integral_constant<std::size_t, std::variant<tag<int>, tag<float>>(tag<float>{}).index()>  ic;

但是,如果我按以下方式更改get_index专长(使用花括号进行初始化,而不是圆括号)

template <typename T, typename... Ts> 
struct get_index<T, std::variant<Ts...>>
    : std::integral_constant<std::size_t, std::variant<tag<Ts>...>{tag<T>()}.index()>
 { };

编译器抱怨但有不同的错误

  

example.cpp

     

(12):错误C2440:“正在初始化”:无法从“初始化列表”转换为“ std :: variant ...>”

     

(12):注意:目标类型没有构造函数

     

(13):注意:请参见对正在编译的类模板实例化'get_index>'的引用

     

编译器返回:2

出于我无法理解的原因,似乎编译器没有将std::variant<tag<Ts>...>内的get_index视为具有所有方法的std::variant