Eu não entendo qual é o problema: no meu código ou no compilador (menos possível). Há um pedaço de código como este:
#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;
}
Tanto o GCC quanto o MSVC o compilam. Eu testei no godbolt com versões diferentes do GCC e MSVC 17 (local) e 19. Aqui está um link: https://godbolt.org/z/Enfm6L .
Mas Clang não o compila e emite um erro:
redefinition of `'TestA<T, std::void_t<typename T::dummy_iterator> >'`
E estou interessado - talvez haja alguma parte do padrão em que esse código esteja incorreto ou talvez algo mais.
Respostas:
Isso provavelmente está relacionado ao CWG 1558 .
É um defeito que foi abordado desde então, mas se a versão do Clang usada ainda não implementa a correção, ele ainda pode considerar ambas as especializações como simplesmente definindo o segundo argumento como
void
e não executando todo o discurso de falha de substituição. A solução alternativa é não usar um alias simplesstd::void_t
, mas uma versão um pouco mais complexaPara um modelo de classe (que é o que o apelido agora significa), a falha de substituição é definida. Conectar isso ao seu exemplo apazigua Clang https://godbolt.org/z/VnkwsM .
fonte
enable_if
withstd::disjunction
(ou a