Почему эта реализация get_index терпит неудачу на VS2017? - PullRequest
0 голосов
/ 06 декабря 2018

Барри дал нам этот великолепный 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, потому что я использую Xcode 9, в котором не было std::variant.Однако из приведенного выше примера Godbolt MCVE видно, что это влияет и на реализацию с std::variant. Я убежден, что проблема либо в приведенном выше коде, либо в компиляторе.)

1 Ответ

0 голосов
/ 06 декабря 2018

Бьюсь об заклад, мои 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 :: вариан ...>»

(12): примечание: у целевого типа нет конструкторов

(13): примечание: см. Ссылку на создание экземпляра шаблона класса 'get_index>', скомпилированного

Возвращен компилятор: 2

Кажется, что по причинам, которые я не могу понять, компилятор не видит std::variant<tag<Ts>...>, внутри get_index, какstd::variant со всеми его методами.

...