¿Hay alguna manera de comprobar si una clase C ++ tiene un constructor predeterminado (distinto de los rasgos de tipo provistos por el comstackdor)?

Se pueden definir clases de rasgos para verificar si una clase C ++ tiene una variable miembro, función o tipo (ver aquí ).

Curiosamente, los ConceptTraits no incluyen rasgos para verificar si una clase de C ++ define un constructor predeterminado o un constructor dado.

¿Se pueden usar rasgos para verificar la presencia del constructor? Si es así, ¿cómo? Si no, ¿por qué no es posible?

Lo siento por responder, puede ser una pregunta.

Google ha encontrado que la razón real por la que no podemos verificar si una clase tiene un constructor o un destructor es que, la técnica conocida utilizada para detectar si una clase tiene un miembro se basa en tomar la dirección del miembro. Pero los constructores y los destructores no tienen nombre, no podemos tomar la dirección de ellos.

Si no podemos tomar la dirección, no veo una manera de hacer que el comstackdor reaccione a una construcción sin instanciarlo directamente, pero en este caso no hay detección en tiempo de comstackción sino un error.

Entonces, para responder a mi propia pregunta, diría que con las técnicas actuales no es posible detectarlas y se necesita compatibilidad con el comstackdor. Pero C ++ ha revelado muchas sorpresas, y las cosas que no eran posibles en un momento dado, se revelaron son posibles usando otra técnica.

Espero que un experto en lenguaje en C ++ lo esté leyendo y pueda dar una explicación más clara.

Los Rasgos de concepto ya no se mantienen, sino que se vuelven parte de los Rasgos de tipo. Y en los documentos de has_trivial_constructor y has_trivial_destructor , los autores de Boost explican claramente que se requiere soporte del comstackdor para que esto funcione.

Una modificación de la respuesta de Potatoswatter

Funciona en gcc-4.6

#include  template< class T > struct identity { typedef T type; }; template struct if_c : identity {}; template< typename T, typename F> struct if_c : identity {}; template struct if_ : if_c< Bool::value, T, F> {}; template< class T > struct is_default_constructible_; template< class T > struct is_default_constructible : if_< std::is_arithmetic, std::true_type, is_default_constructible_ >::type { }; template< class T > struct is_default_constructible_ { template class Acessible : public D { friend class is_default_constructible_; public: //using D::D; may be needed once N2540 is implemented }; template class receive_size{}; template< class U > static int sfinae( receive_size< sizeof Acessible() > * ); template< class U > static char sfinae( ... ); public: enum { value = sizeof( sfinae(0) ) == sizeof(int) }; }; struct p { p(); }; class q { q(); }; class r { r(int); }; #include  using namespace std; int main() { cerr << is_default_constructible::value << endl // outputs 1 << is_default_constructible

::value << endl << is_default_constructible::value << endl << is_default_constructible::value << endl; // outputs 0 }

# g ++ - mp-4.6 --std = c ++ 0x -Wall test.cpp && ./a.out
1
1
0
0

Advertencia: algunos análisis a continuación están obsoletos a partir de C ++ 11. En C ++ 11, la verificación de acceso se realiza antes de la instanciación y la violación de acceso no es un error. Por lo tanto, el código adjunto puede ser más compatible. No lo he vuelto a analizar.


Soy bastante nuevo en SFINAE. Hoy se me ocurrió colocar una expresión de prueba dentro de un sizeof dentro de un parámetro de plantilla en un tipo de argumento de función.

De acuerdo con N2634, esto no está mal, pero es muy poco práctico. ( EDITAR: parece ser compatible con C ++ 0x FCD.) Solo puede volverse positivo o no comstackrse en GCC 4.2; GCC 4.5 obtiene un 3 de 3 para mis casos de prueba.

Las reglas de SFINAE se ampliaron (en este caso) desde C ++ 03 en el FCD. Nuevo §14.8.2 / 8 (énfasis mío):

Si una sustitución da como resultado un tipo o expresión no válida , el tipo de deducción falla. Un tipo o expresión inválida es aquella que estaría mal formada si se escribiera utilizando los argumentos sustituidos. La verificación de acceso no se realiza como parte del proceso de sustitución. En consecuencia, cuando la deducción tiene éxito, un error de acceso aún puede resultar cuando se crea una instancia de la función. Solo los tipos y expresiones no válidos en el contexto inmediato del tipo de función y sus tipos de parámetros de plantilla pueden provocar un error de deducción. [Nota: la evaluación de los tipos y expresiones sustituidos puede dar como resultado efectos secundarios tales como la instanciación de especializaciones de plantilla de clase y / o especializaciones de plantilla de función, la generación de funciones implícitamente definidas, etc. Tales efectos secundarios no están en el “inmediato contexto “y puede dar lugar a que el progtwig esté mal formado.

 template< class T > class is_default_constructible { template class receive_size{}; template< class U > static int sfinae( receive_size< sizeof U() > * ); template< class U > static char sfinae( ... ); public: enum { value = sizeof( sfinae(0) ) == sizeof(int) }; }; class q { q(); }; class r { r(int); }; #include  using namespace std; int main() { cerr << is_default_constructible::value << endl // outputs 1 // fails to compile: access violation // FCD demands that access violations be unrecoverable // indeed, it's murky: q is default-constructible, but only "rarely" //<< is_default_constructible::value << endl << is_default_constructible::value << endl; // outputs 0 } 

MSDN dice que el encabezado define has_default_constructor y dichos rasgos.

http://msdn.microsoft.com/en-us/library/bb982179.aspx

Es posible que desee comprobar este ejemplo de código tomado de libstdc ++ en Gcc 4.6.1 y que modifiqué ligeramente para trabajar con MSVC 2010 :

/! \: is_default_constructible devuelve true incluso si el constructor predeterminado es privado o protegido, todavía no puedo encontrar una manera de resolver esto, ¿alguna idea?):

 namespace std { namespace detail { template struct __and_ : public conditional<_B1::value, _B2, _B1>::type { }; template struct __not_ : public integral_constant { }; template struct __is_array_known_bounds : public integral_constant::value > 0)> { }; template struct __is_array_unknown_bounds : public __and_, __not_<_tp>>>::type { }; struct __do_is_default_constructible_impl { template static true_type __test(int,decltype(_Tp())* a = 0); template static false_type __test(...); }; template struct __is_default_constructible_impl : public __do_is_default_constructible_impl { typedef decltype(__test<_tp>(0)) type; }; template struct __is_default_constructible_atom : public __and_<__not_>, __is_default_constructible_impl<_tp>>::type { }; template::value> struct __is_default_constructible_safe; // The following technique is a workaround for a current core language // restriction, which does not allow for array types to occur in // functional casts of the form T(). Complete arrays can be default- // constructed, if the element type is default-constructible, but // arrays with unknown bounds are not. template struct __is_default_constructible_safe<_Tp, true> : public __and_<__is_array_known_bounds<_tp>, __is_default_constructible_atom::type>>::type { }; template struct __is_default_constructible_safe<_Tp, false> : public __is_default_constructible_atom<_tp>::type { }; } // namespace detail /// is_default_constructible template struct is_default_constructible : public integral_constant::value)> { }; } 

utilizar :

 class DefaultConstructible { public: DefaultConstructible() {} }; class NotDefaultConstructible { public: NotDefaultConstructible(int i) {} }; std::is_default_constructible::value // -> true std::is_default_constructible::value // -> false 

Después de dertwigr mucha sangre, sudor y lágrimas, finalmente encontré una forma que funciona en cada comstackdor que probé:

 template struct is_default_constructible; template<> struct is_default_constructible { protected: // Put base typedefs here to avoid pollution struct twoc { char a, b; }; template struct test { typedef char type; }; public: static bool const value = false; }; template<> struct is_default_constructible<>::test { typedef twoc type; }; template struct is_default_constructible : is_default_constructible<> { private: template static typename test::type sfinae(U*); template static char sfinae(...); public: static bool const value = sizeof(sfinae(0)) > 1; };