Nie rozumiem, na czym polega problem: ani w moim kodzie, ani w kompilatorze (mniej możliwe). Jest taki kod:
#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;
}
Kompilują go zarówno GCC, jak i MSVC. Przetestowałem go na Godbolt z inną wersją GCC i MSVC 17 (lokalna) i 19. Oto link: https://godbolt.org/z/Enfm6L .
Ale Clang go nie kompiluje i emituje błąd:
redefinition of `'TestA<T, std::void_t<typename T::dummy_iterator> >'`
I jestem zainteresowany - może jest jakaś część standardu, w której ten fragment kodu jest niepoprawny, a może coś innego.
Odpowiedzi:
Jest to bardzo prawdopodobne w odniesieniu do CWG 1558 .
Jest to wada, która została już rozwiązana, ale jeśli używana wersja Clanga nie implementuje jeszcze poprawki, może nadal uważać obie specjalizacje za po prostu zdefiniowanie drugiego argumentu jako
void
, i nie wykonanie całej spiel niepowodzeń podmiany. Obejściem tego problemu jest nie używanie zwykłego aliasustd::void_t
, ale zamiast tego nieco bardziej złożona wersjaW przypadku szablonu klasy (który teraz oznacza alias) zdefiniowano błąd podstawienia. Podłączenie tego do twojego przykładu uspokaja Clanga https://godbolt.org/z/VnkwsM .
źródło
enable_if
zstd::disjunction
(lub wymaga klauzuli)