Je ne comprends pas quel est le problème: soit dans mon code, soit dans le compilateur (moins possible). Il y a un morceau de code comme celui-ci:
#include <iostream>
#include <type_traits>
#include <set>
template<typename T, typename = void>
struct TestA: std::false_type {};
template<typename T>
struct TestA<T, std::void_t<typename T::reverse_iterator>> : std::true_type {};
template<typename T>
struct TestA<T, std::void_t<typename T::dummy_iterator>> : std::true_type {};
int main()
{
std::cout << TestA<std::set<int>>::value;
}
GCC et MSVC le compilent. Je l'ai testé sur godbolt avec différentes versions de GCC et MSVC 17 (local) et 19. Voici un lien: https://godbolt.org/z/Enfm6L .
Mais Clang ne le compile pas et émet une erreur:
redefinition of `'TestA<T, std::void_t<typename T::dummy_iterator> >'`
Et je suis intéressé - peut-être qu'il y a une partie de la norme où ce morceau de code est incorrect ou peut-être autre chose.
Réponses:
Ceci est très probablement lié au CWG 1558 .
C'est un défaut qui a été corrigé depuis, mais si la version de Clang que vous avez utilisée n'implémente pas encore le correctif, il peut toujours considérer les deux spécialisations comme définissant simplement le deuxième argument comme
void
, et ne faisant pas tout le spiel d'échec de substitution. La solution consiste à ne pas utiliser un alias simplestd::void_t
, mais plutôt une version légèrement plus complexePour un modèle de classe (qui correspond maintenant à l'alias), l'échec de substitution est défini. Brancher cela dans votre exemple apaise Clang https://godbolt.org/z/VnkwsM .
la source
enable_if
avecstd::disjunction
(ou une clause requiert)