6 votes

Pourquoi cette implémentation de get_index échoue-t-elle sur VS2017 ?

Barry nous a donné ce magnifique get_index pour les variantes :

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

A utiliser comme suit :

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

Il fonctionne parfaitement dans Clang (OSX).

Mais dans Visual Studio 2017 Je reçois les éléments suivants :

<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

Je ne vois pas pourquoi. Des idées à ce sujet ?

(Pour tout vous dire, dans mon projet, j'utilise en fait mpark::variant parce que j'ai utilisé Xcode 9, qui n'a pas eu de std::variant . Cependant, vous pouvez voir dans le MCVE de Godbolt ci-dessus que cela affecte la mise en œuvre avec std::variant également. Je suis convaincu que le problème se situe soit dans le code ci-dessus, soit dans le compilateur).

2voto

max66 Points 4276

Je parie mes 2 cents qu'il s'agit d'un bug de compilation.

Je constate que si j'écris dans main()

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

le compilateur ne se plaint pas.

Il ne se plaint pas non plus si j'écris une fonction modèle comme suit

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

et je l'appelle, de main() , avec

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

Il n'y a aucun problème à déclarer la variable suivante dans main()

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

Mais si je modifie le get_index comme suit (en utilisant des accolades pour l'initialisation au lieu de parenthèses rondes)

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

le compilateur se plaint mais avec une erreur différente

exemple.cpp

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

(12) : note : le type cible n'a pas de constructeurs

(13) : note : référence à l'instanciation du modèle de classe "get_index>" en cours de compilation

Compilateur retourné : 2

Il semble que, pour des raisons que je ne comprends pas, le compilateur ne voit pas std::variant<tag<Ts>...> , à l'intérieur get_index , en tant que std::variant avec toutes ses méthodes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X