Existe-t-il un moyen de tester si une classe C ++ a un constructeur par défaut (autre que les traits de type fournis par le compilateur)?

Des classes de caractères peuvent être définies pour vérifier si une classe C ++ a une variable membre, une fonction ou un type (voir ici ).

Curieusement, les ConceptTraits n’incluent pas de traits permettant de vérifier si une classe C ++ définit un constructeur par défaut ou un constructeur donné?

Peut-on utiliser des traits pour vérifier la présence du constructeur? Si oui comment? Si non, pourquoi ce n’est pas possible?

Désolé pour répondre peut propre question.

J’ai trouvé sur Google que la raison pour laquelle nous ne pouvons pas vérifier si une classe a un constructeur ou des destructeurs est que la technique connue utilisée pour détecter si une classe a un membre est basée sur la prise de l’adresse du membre. Mais les constructeurs et les destructeurs n’ont pas de nom, nous ne pouvons pas en prendre l’adresse.

Si nous ne pouvons pas prendre l’adresse, je ne vois pas le moyen de faire réagir le compilateur à une construction sans l’instancier directement, mais dans ce cas, il n’y a pas de détection à la compilation, mais une erreur.

Donc, pour répondre à ma propre question, je dirais qu’avec les techniques actuelles, il n’est pas possible de les détecter et qu’un support du compilateur est nécessaire. Mais C ++ a révélé beaucoup de sursockets et des choses impossibles à un moment donné ont été révélées via une autre technique.

J’espère qu’un expert en langage C ++ lit cela et peut donner une explication plus claire.

Les traits de concept ne sont plus conservés, mais font partie des caractères de type. Et dans la documentation de has_sortingvial_constructor et de has_sortingvial_destructor , les auteurs de Boost expliquent clairement que le support du compilateur est requirejs pour que cela fonctionne.

Une modification de la réponse de Potatoswatter

Fonctionne sur 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

Attention: certaines parsings ci-dessous sont obsolètes à partir de C ++ 11. En C ++ 11, la vérification d’access est effectuée avant l’instanciation et la violation d’access n’est pas une erreur. Par conséquent, le code ci-joint peut être plus conforme. Je ne l’ai pas ré-analysé.


Je suis assez nouveau à SFINAE. Aujourd’hui, j’ai eu l’idée de placer une expression de test dans un sizeof dans un paramètre de modèle dans un type d’argument de fonction.

Selon N2634, ce n’est pas faux, mais extrêmement imputable à l’instant. ( EDIT: semble conforme à C ++ 0x FCD.) Il ne peut que renvoyer positif ou échouer lors de la compilation dans GCC 4.2; GCC 4.5 obtient une note de 3 sur 3 pour mes cas de test.

Les règles SFINAE ont été élargies (dans ce cas) depuis C ++ 03 dans la FCD. Nouveau § 14.8.2 / 8 (c’est moi qui souligne):

Si une substitution entraîne un type ou une expression non valide , la déduction de type échoue. Un type ou une expression non valide est une forme qui serait mal formée si elle était écrite en utilisant les arguments substitués. La vérification d’access n’est pas effectuée dans le cadre du processus de substitution. Par conséquent, lorsque la déduction réussit, une erreur d’access peut toujours résulter de l’instanciation de la fonction. Seuls les types et les expressions non valides dans le contexte immédiat du type de fonction et de ses types de parameters de modèle peuvent entraîner un échec de la déduction. [Remarque: l’évaluation des types et des expressions substitués peut entraîner des effets indésirables tels que l’instanciation de spécialisations de modèles de classe et / ou de modèles de fonctions, la génération de fonctions implicitement définies, etc. Ces effets indésirables contexte “et peut entraîner une mauvaise formation du programme.

 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 indique que l’en-tête définit has_default_constructor et de tels traits.

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

Vous voudrez peut-être vérifier cet exemple de code tiré de libstdc ++ dans Gcc 4.6.1 et que j’ai légèrement modifié pour fonctionner avec MSVC 2010 :

/! \: is_default_constructible renvoie true même si le constructeur par défaut est privé ou protégé, je ne trouve toujours pas le moyen de résoudre ce problème, aucune idée?):

 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 // ressortingction, 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)> { }; } 

utilisation :

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

Après avoir versé beaucoup de sang, de sueur et de larmes, j’ai finalement trouvé un moyen qui fonctionne sur chaque compilateur que j’ai essayé:

 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; };