为什么此get_index实现在VS2017上失败? [英] Why does this get_index implementation fail on VS2017?

查看:148
本文介绍了为什么此get_index实现在VS2017上失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Barry给了我们这个精美的get_index变体:

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中我得到了以下内容:

<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的Xcode 9,但是,从上面的Godbolt MCVE中可以看到,这也会影响std::variant的实现.我确信问题出在上述代码中,或在编译器中.)

解决方案

我打赌我的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; }

我用

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

来称呼它

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

由于我不明白的原因,似乎编译器看不到get_index内的std::variant<tag<Ts>...>作为具有所有方法的std::variant.

Barry gave us 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()>
{ };

To be used as follows:

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

It works great in Clang (OSX).

But in Visual Studio 2017 I'm getting the following:

<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

I can't see why. Any ideas?

(Full disclosure: in my project I'm actually using mpark::variant because I have been using Xcode 9, which didn't have std::variant. However, you can see from the Godbolt MCVE above that this affects the implementation with std::variant as well. I'm convinced the problem is either in the code above, or in the compiler.)

解决方案

I bet my 2 cents that is a compiler bug.

I see that if I write in main()

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

the compiler doesn't complain.

And doesn't complain also if I write a template function as follows

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

and I call it, from main(), with

foo<int, long, int, long long>();

No problem also declaring the following variable in main()

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

But if I change the get_index specialization as follows (using braces for initialization instead of round parentheses)

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()>
 { };

the compiler complain but with a different error

example.cpp

(12): error C2440: 'initializing': cannot convert from 'initializer list' to 'std::variant...>'

(12): note: The target type has no constructors

(13): note: see reference to class template instantiation 'get_index>' being compiled

Compiler returned: 2

Seems that, for reasons I can't understand, the compiler doesn't see std::variant<tag<Ts>...>, inside get_index, as a std::variant with all it's methods.

这篇关于为什么此get_index实现在VS2017上失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆