No entiendo cuál es el problema: ya sea en mi código o en el compilador (menos posible). Hay un 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 GCC como MSVC lo compilan. Lo probé en godbolt con diferentes versiones de GCC y MSVC 17 (local) y 19. Aquí hay un enlace: https://godbolt.org/z/Enfm6L .
Pero Clang no lo compila y emite un error:
redefinition of `'TestA<T, std::void_t<typename T::dummy_iterator> >'`
Y estoy interesado, tal vez hay alguna parte del estándar en la que este código es incorrecto o tal vez algo más.
Respuestas:
Es muy probable que esto esté relacionado con CWG 1558 .
Es un defecto que se abordó desde entonces, pero si la versión de Clang que usó aún no implementa la solución, aún puede considerar ambas especializaciones simplemente definiendo el segundo argumento como
void
, y no haciendo toda la división de fallas de sustitución. La solución alternativa es no usar un alias simplestd::void_t
, sino una versión un poco más complejaPara una plantilla de clase (que es lo que ahora representa el alias), se define el error de sustitución. Conectar eso a su ejemplo apacigua Clang https://godbolt.org/z/VnkwsM .
fuente
enable_if
constd::disjunction
(o una cláusula