c++ visual-studio-2015 c++14 sfinae

c++ - void_t falla en Visual Studio 2015



visual-studio-2015 c++14 (2)

Esto parece un problema de SFINAE en VC ++. El uso de un decltype dependiente en el argumento de la plantilla de la especialización parcial de una plantilla de clase aún no es compatible. Debería funcionar en VS 2015 Update 1.

No entiendo por qué la siguiente prueba siempre falla con Visual Studio 2015 (los activadores static_assert):

#include <type_traits> using namespace std; template<class T> using try_assign = decltype(declval<T&>() = declval<T const&>()); template<class, class = void> struct my_is_copy_assignable : false_type {}; template<class T> struct my_is_copy_assignable<T, void_t<try_assign<T>>> : true_type {}; int main() { static_assert(my_is_copy_assignable<int>::value, "fail"); return 0; }

Es básicamente la transcripción del ejemplo de uso de void_t de Walter E Brown en su presentación de cppcon 2014 "Modern Template Metaprogramming - Un compendio".

Es importante tener en cuenta que esta versión alternativa funciona, por lo que no creo que el problema radique en el soporte incompleto de MSVC para la expresión SFINAE.

template<class T> using try_assign = decltype(declval<T&>() = declval<T const&>()); template<class T> struct my_is_copy_assignable { template<class Q, class = try_assign<Q>> static true_type tester(Q&&); static false_type tester(...); using type = decltype(tester(declval<T>())); };

Sé sobre std::is_copy_assignable pero solo me interesa entender mejor las diversas técnicas de metaprogramación disponibles en las diferentes revisiones de C ++. Leí varios hilos sobre void_t en la web, pero aún no entiendo por qué falla este ejemplo.

Lo interesante es que con GCC 4.8.2 funciona bien (utilizando la solución CWG 1558, que es la misma que la versión de Microsoft).

¿Es un error conocido de Visual Studio o estoy haciendo algo mal?


Walter E. Brown en CppCon 2014 también mencionó la siguiente factorización que permite reemplazar try_assign con una condición arbitraria.

#include <type_traits> #include <utility> template<class T> using try_assign = decltype(std::declval<T&>() = std::declval <T const &>()); template<class T, template<class> class Op, class = void> struct is_valid : std::false_type { }; template<class T, template<class> class Op> struct is_valid<T, Op, std::void_t<Op<T>>> : std::true_type { }; template<class T> using is_copy_assignable = is_valid<T, try_assign>; int main() { static_assert(is_copy_assignable<int>::value, "fail"); return 0; }

Esta factorización compila OK con VS 2015. Ahora elimine is_copy_assignable y sustitúyalo por is_valid . Usted termina con el código que presentó y que no se compila (VS 2015).

Esto sugiere que hay un error en VS 2015 y no está relacionado con CWG 1558. En el problema de CWG, el estándar no estaba claro si los argumentos no utilizados en las especializaciones de plantillas de alias podrían dar como resultado un fallo de sustitución o simplemente se ignoran.