triangulos trazar tecnico regla primaria planas paso para mediante geométricas geometricas figuras ejercicios dibujo construcciones construccion con compás compas como c++ templates metaprogramming

c++ - trazar - figuras geometricas con compas



¿Por qué el uso de dos sizeofs funciona para verificar si una clase es construible por defecto, pero una no? (2)

(Mi respuesta está muy bien informada por la respuesta previa de DS).

Antes que nada, fíjate que tienes class is_okay { typedef void type; } class is_okay { typedef void type; } , es decir, type es un miembro privado de is_okay . Esto significa que no es realmente visible fuera de la clase y, por lo tanto,

template< class U > static yes sfinae( typename is_equal< sizeof U(), sizeof U() >::type * );

nunca tendrá éxito Sin embargo, SFINAE originalmente no se aplicaba a esta situación en C ++ 98; no fue hasta la resolución del DR 1170 que "la verificación de acceso [comenzó siendo] realizada como parte del proceso de sustitución". [1]

(Sorprendentemente, Paolo Carlini escribió esa entrada en el blog hace solo 10 días, por lo que su tiempo con esta pregunta es impecable. En casos como este, según Carlini, GCC anterior a la 4.8 no accedió a la verificación durante SFINAE en absoluto. por qué no vio a GCC quejarse del carácter privado del type . Para ver el comportamiento correcto, tendría que estar utilizando un GCC de la cima del árbol desde hace menos de dos semanas.)

Clang (top-of-tree) sigue el modo DR en -std=c++11 , pero da el error esperado en su modo predeterminado C ++ 03 (es decir, Clang no sigue el DR en el modo C ++ 03) . Esto es un poco extraño, pero tal vez lo hacen por compatibilidad con versiones anteriores.

Pero de todos modos , en realidad no quiere que el type sea ​​privado en primer lugar. Lo que quisiste escribir es struct is_equal y struct is_okay .

Con este cambio, Clang pasa todos sus casos de prueba. GCC 4.6.1 pasa todos sus casos de prueba también, a excepción de int[100] . GCC piensa que int[100] está bien, mientras que usted está afirmando que no está bien.

Pero otro problema con su código es que no prueba lo que cree que está probando. El estándar de C ++, cláusula 8.5 # 10, dice muy claramente: [2]

Un objeto cuyo inicializador es un conjunto vacío de paréntesis, es decir, () , se inicializará en valor.

Entonces, cuando escribe sizeof U() , no está probando si U puede ser inicializado -inicializado; ¡estás probando si puede ser un valor inicializado!

...¿O eres tu? Al menos en algunos de mis casos de prueba, los mensajes de error de GCC indicaban que U() se interpretaba como el nombre de un tipo - "función que devuelve U " - y que era por lo que int[100] comportaba de manera diferente. No veo cómo ese comportamiento es válido, pero realmente no entiendo las sutilezas sintácticas aquí.

Si realmente quiere probar la inicialización predeterminada , debe usar algo como sizeof *new U cualquier lugar donde tenga sizeof U() .

Por cierto, int[100] es default-initializable, period. El estándar es claro en lo que significa inicializar por defecto un tipo de matriz.

Finalmente, me pregunto si una causa del comportamiento alocado en tu código es que estás tratando de pasar un 0 sin adornos (que es de tipo int ) a una función cuyo conjunto de sobrecargas incluye una función que toma void * y otra que toma ... . Pude entender totalmente si un compilador escogió el incorrecto en ese caso. Lo mejor sería intentar pasar 0 a una función que toma int .

Poniéndolo todo junto, aquí hay una versión de tu código que funciona perfectamente para mí (es decir, sin aserciones-fallas) tanto en ToT Clang como en GCC 4.6.1.

template< class T > class is_default_constructible { typedef int yes; typedef char no; template<int x> struct is_okay { typedef int type; }; template< class U > static yes sfinae( typename is_okay< sizeof (*new U) >::type ); template< class U > static no sfinae( ... ); public: enum { value = sizeof( sfinae<T>(0) ) == sizeof(yes) }; }; #if __has_feature(cxx_static_assert) #define BOOST_STATIC_ASSERT(x) static_assert(x, "or fail") #else #define dummy2(line) dummy ## line #define dummy(line) dummy2(line) #define BOOST_STATIC_ASSERT(x) int dummy(__COUNTER__)[(x) - 1] #endif #include <string> BOOST_STATIC_ASSERT( !is_default_constructible<int()>::value ); BOOST_STATIC_ASSERT( is_default_constructible<bool>::value ); BOOST_STATIC_ASSERT( is_default_constructible<std::string>::value ); BOOST_STATIC_ASSERT( is_default_constructible<int[100]>::value ); BOOST_STATIC_ASSERT( is_default_constructible<const std::string>::value ); struct NotDefaultConstructible { const int x; NotDefaultConstructible( int a ) : x(a) {} }; BOOST_STATIC_ASSERT( !is_default_constructible<NotDefaultConstructible>::value ); struct DefaultConstructible { const int x; DefaultConstructible() : x(0) {} }; BOOST_STATIC_ASSERT( is_default_constructible<DefaultConstructible>::value );

Utilicé el código de " ¿Hay alguna manera de probar si una clase C ++ tiene un constructor predeterminado (distinto de los rasgos de tipo proporcionados por el compilador)? ".

Lo modifiqué ligeramente para trabajar con todos mis casos de prueba:

template< class T > class is_default_constructible { typedef int yes; typedef char no; // the second version does not work #if 1 template<int x, int y> class is_equal {}; template<int x> class is_equal<x,x> { typedef void type; }; template< class U > static yes sfinae( typename is_equal< sizeof U(), sizeof U() >::type * ); #else template<int x> class is_okay { typedef void type; }; template< class U > static yes sfinae( typename is_okay< sizeof U() >::type * ); #endif template< class U > static no sfinae( ... ); public: enum { value = sizeof( sfinae<T>(0) ) == sizeof(yes) }; };

¿Por qué funciona correctamente con la versión del argumento de dos plantillas pero no con la normal (set #if 0 )? ¿Es esto un error del compilador? Estoy usando Visual Studio 2010.

Usé las siguientes pruebas:

BOOST_STATIC_ASSERT( is_default_constructible<int>::value ); BOOST_STATIC_ASSERT( is_default_constructible<bool>::value ); BOOST_STATIC_ASSERT( is_default_constructible<std::string>::value ); BOOST_STATIC_ASSERT( !is_default_constructible<int[100]>::value ); BOOST_STATIC_ASSERT( is_default_constructible<const std::string>::value ); struct NotDefaultConstructible { const int x; NotDefaultConstructible( int a ) : x(a) {} }; BOOST_STATIC_ASSERT( !is_default_constructible<NotDefaultConstructible>::value ); struct DefaultConstructible { const int x; DefaultConstructible() : x(0) {} }; BOOST_STATIC_ASSERT( is_default_constructible<DefaultConstructible>::value );

Estoy realmente perdido aquí:

  1. Dos pruebas fallan con la otra versión: int[100] y NotDefaultConstructible . Todas las pruebas tienen éxito con la versión del argumento de dos plantillas.
  2. Visual Studio 2010 no es compatible con std::is_default_constructible . Sin embargo, mi pregunta es acerca de por qué hay alguna diferencia en las dos implementaciones y por qué una funciona y la otra no.

Esto parece casi con seguridad un artefacto (error) del compilador, ya que g ++ se comporta (y falla) de manera diferente. Solo puedo adivinar por qué VS se comporta de manera diferente, pero una suposición que parece razonable es que esta clase:

template<int x> class is_okay { typedef void type; };

tiene la misma definición independientemente del parámetro de la plantilla, por lo que tal vez el compilador omita un paso al analizar static sfinae( typename is_okay< sizeof U() >::type * ); y lo considera bien definido sin mirar de cerca el parámetro de is_okay . Entonces, piensa que todo es predecible y construible.

Por qué ni VS ni g ++ están is_okay::type por que is_okay::type sea ​​privado, no lo sé. Parece que ambos deberían estarlo.

g ++, por otro lado, trata ambas versiones como equivalentes. En ambos, sin embargo, da un error diferente para int[100] . Ese es discutible si debe ser predecible o no. Parece que piensas que no debería ser. g ++ 47 std::is_default_constructible cree que es! Para obtener ese comportamiento (que probablemente sea más estándar), puede reemplazar T con typename boost::remove_all_extents<T>::type en la línea enum .