Question

Après avoir répondu à la question que je tentais de trouver is_complete modèle dans Boost J'ai réalisé qu'il n'y avait pas de tel modèle dans Boost.TypeTraits. Pourquoi ce modèle n'existe-t-il pas dans la bibliothèque Boost? A quoi ça devrait ressembler?

//! Check whether type complete
template<typename T>
struct is_complete
{   
  static const bool value = ( sizeof(T) > 0 );
};

...

// so I could use it in such a way
BOOST_STATIC_ASSERT( boost::is_complete<T>::value );

Le code ci-dessus n'est pas correct car il est illégal d'appliquer sizeof à un type incomplet. Quelle sera la bonne solution? Est-il possible d'appliquer SFINAE dans ce cas?

Eh bien, ce problème ne pourrait pas être résolu en général sans enfreindre la règle ODR , mais il existe une solution spécifique à la plate-forme qui fonctionne pour moi .

Était-ce utile?

La solution

La réponse donnée par Alexey Malistov peut être utilisée sur MSVC avec une modification mineure:

namespace 
{
    template<class T, int discriminator>
    struct is_complete {  
      static T & getT();   
      static char (& pass(T))[2]; 
      static char pass(...);   
      static const bool value = sizeof(pass(getT()))==2;
    };
}
#define IS_COMPLETE(X) is_complete<X,__COUNTER__>::value

Malheureusement, la macro prédéfinie COUNTER ne fait pas partie du standard. Elle ne fonctionnerait donc pas avec tous les compilateurs.

Autres conseils

template<class T>
struct is_complete {
    static T & getT();
    static char (& pass(T))[2];
    static char pass(...);

    static const bool value = sizeof(pass(getT()))==2;
};

Il est peut-être un peu tardif, mais aucune solution C ++ 11 ne fonctionnait jusqu'ici pour les types complet et abstrait.

Alors, vous y êtes.

Avec VS2015 (v140), g ++ > = 4.8.1, clang > = 3,4, cela fonctionne:

template <class T, class = void>
struct IsComplete : std::false_type
{};

template <class T>
struct IsComplete< T, decltype(void(sizeof(T))) > : std::true_type
{};

Merci à Bat-Ulzii Luvsanbat: https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update -1 /

Avec VS2013 (V120):

namespace Details
{

    template <class T>
    struct IsComplete
    {
        typedef char no;
        struct yes { char dummy[2]; };

        template <class U, class = decltype(sizeof(std::declval< U >())) >
        static yes check(U*);

        template <class U>
        static no check(...);

        static const bool value = sizeof(check< T >(nullptr)) == sizeof(yes);
    };

} // namespace Details


template <class T>
struct IsComplete : std::integral_constant< bool, Details::IsComplete< T >::value >
{};

Celui-ci s’inspire des internets et de affirmation statique le nom de modèle T n'est pas complet?

Je crains que vous ne puissiez pas mettre en œuvre un tel is_complete type. L'implémentation donnée par @Alexey ne parvient pas à compiler sous G ++ 4.4.2 et G ++ 4.5.0:

  

erreur: l'initialisation de l'argument 1 de & # 8216; caractère statique (& et; is_complete :: pass (T)) [2] [avec T = Foo] & # 8217;

Sur mon Mac, avec G ++ 4.0.1, évaluer is_complete<Foo>::valuestruct Foo; est incomplet, donne <<>, ce qui est encore pire qu'une erreur de compilation.

true peut être à la fois complet et incomplet dans le même programme, en fonction de l'unité de traduction, mais reste toujours du même type. En conséquence, comme indiqué ci-dessus, T est toujours du même type.

Donc, si vous respectez ODR , il n'est pas possible d'avoir is_complete<T> une évaluation différente. valeurs en fonction de l'endroit où il est utilisé; sinon, cela signifierait que vous avez différentes définitions pour __COUNTER__ ce qui est interdit par ODR.

EDIT: En tant que réponse acceptée, j’ai moi-même piraté une solution qui utilise la macro is_complete<T, int> pour instancier un type IS_COMPLETE différent chaque fois que la macro <=> est utilisée. Cependant, avec gcc, je ne pouvais pas faire travailler SFINAE en premier lieu.

Pour résoudre ce problème, vous devez exécuter le calcul dans l'argument par défaut du modèle de trait, car toute tentative de modification de la définition d'un modèle enfreint la règle ODR (bien qu'une combinaison de __COUNTER__ et namespace {} puisse contourner le problème ODR).

Ceci est écrit en C ++ 11 mais peut être ajusté pour fonctionner en mode C ++ 03 d'un compilateur compatible C ++ 11 moyennement récent.

template< typename t >
typename std::enable_if< sizeof (t), std::true_type >::type
is_complete_fn( t * );

std::false_type is_complete_fn( ... );

template< typename t, bool value = decltype( is_complete_fn( (t *) nullptr ) )::value >
struct is_complete : std::integral_constant< bool, value > {};

démonstration en ligne.

L'argument par défaut est évalué à l'endroit où le modèle est nommé, afin qu'il puisse basculer de manière contextuelle entre différentes définitions. Une spécialisation et une définition différentes ne sont pas nécessaires à chaque utilisation; il vous en faut seulement un pour true et un pour false.

La règle est donnée dans & # 167; 8.3.6 / 9, qui s'applique également aux arguments par défaut de la fonction et aux arguments de modèle par défaut:

  

Les arguments par défaut sont évalués chaque fois que la fonction est appelée.

Mais attention, son utilisation dans un modèle enfreint à coup sûr l'ODR. Un modèle instancié sur un type incomplet ne doit rien faire d'autre que s'il était instancié sur un type complet. Personnellement, je ne veux cela que pour un static_assert.

Incidemment, ce principe peut également être utile si vous souhaitez aller dans l’autre sens et implémenter les fonctionnalités de <=> l’utilisation de modèles et la surcharge.

Il suffit de signaler qu'une réponse (non donnée par moi) à une question non liée donne une solution au is_complete<T> modèle.

La réponse est ici . Je ne le colle pas ci-dessous afin de ne pas obtenir un crédit par erreur.

Je ne trouve rien dans la norme qui garantisse que sizeof sur un type incomplet donnera 0. Il faut toutefois que si T est incomplet à un moment donné, mais complété ultérieurement dans cette unité de traduction, toutes les références pour que T fasse référence au même type - ainsi que je l'ai lu, même si T est incomplet lorsque votre modèle a été invoqué, il serait nécessaire de dire qu'il était complet si T est terminé quelque part dans cette unité de traduction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top