for compile templates c++11 gcc clang sfinae

templates - compile - llvm 3.7 1



C++ 11: SFINAE en parĂ¡metros de plantilla, GCC vs Clang (1)

Quiero implementar una pequeña clase de rasgo para determinar si un tipo ha sobrecargado el operator() correctamente, de modo que pueda consultar un tipo como ese:

FunctorCheck<F, void(int, char)>::value

Originalmente, tuve una idea de cómo implementar esto a partir de esta pregunta , pero después de ver una conferencia de Cppcon sobre TMP , caí en la cuenta de que este problema podría resolverse de forma mucho más elegante. Esto es lo que se me ocurrió, y esto compila y funciona sin problemas en Clang 3.5.0:

template <typename ...> using void_t = void; template <typename Functor, typename ... Args> using FunctorReturn = decltype(declval<Functor>()(declval<Args>()...)); template <typename Functor, typename Signature, typename = void> struct FunctorCheck: public std::false_type {}; template <typename Functor, typename R, typename ... Args> struct FunctorCheck<Functor, R(Args...), void_t<FunctorReturn<Functor, Args ...>> // SFINAE can kick in here > : public std::is_same<R, FunctorReturn<Functor, Args ...>>::type {};

Como habrás notado, estoy usando el propuesto C ++ 17 void_t para explotar SFINAE en los parámetros de plantilla de la especialización. Cuando FunctorReturn recibe un tipo de Functor que es incompatible con la lista de argumentos, void_t<FunctorReturn<Functor, Args ...>> estará mal formado, SFINAE se activará y se creará una instancia de la versión no especializada. Si la expresión anterior está bien formada, std::is_same compara los tipos de devolución para determinar si tenemos una coincidencia.

En la conferencia mencionada anteriormente, Walter Brown menciona que esta técnica ha funcionado desde el día 1 en Clang, y no ha funcionado en GCC desde el día 1, simplemente porque eligieron diferentes implementaciones en algo que el estándar no pudo especificar. Sin embargo, dado que esta versión es mucho más elegante que lo que tenía antes, ¿hay algo que pueda hacer para hacer esta compilación en GCC (> = 4.9)?

(Además, ¿alguien tiene alguna pista sobre cómo se comportaría esto en las versiones recientes de Visual Studio?)


Este fue el CWG número 1558 . La parte no especificada fue el tratamiento de los argumentos no utilizados en una plantilla de alias. En GCC <5.0 los argumentos no utilizados no pueden dar como resultado una falla de sustitución, por void_t tanto, void_t no puede verificar su invocación de functor , e intenta crear una instancia de especialización de plantilla de clase, lo que da como resultado un error void_t .

Una solución para GCC (<5.0) es la siguiente implementación:

template <typename...> struct voider { using type = void; }; template <typename... Ts> using void_t = typename voider<Ts...>::type;

MANIFESTACIÓN