2

Considérons le modèle de fonction suivante:Stratégie automatique d'évaluation Sélection en C++

template<typename T> void Foo(T) 
{ 
    // ... 
} 

sémantique passe par valeur de sens que si T se trouve être un type intégral, ou au moins un type qui est pas cher à copier. En revanche, l'utilisation de la sémantique de référence par rapport à [const] a plus de sens si T s'avère être un type coûteux à copier.

Supposons pour une seconde que vous écrivez une bibliothèque. Idéalement, en tant que responsable de la mise en œuvre d'une bibliothèque, votre travail consiste à fournir à vos clients une API propre, à la fois générique et efficace. Comment alors, fournissez-vous une interface générique qui s'adresse aux deux types de stratégies de passage d'argument?


Voici ma première tentative d'obtenir que cela fonctionne:

#include <boost/type_traits.hpp> 

template<typename T> struct DefaultCondition 
{ 
    enum {value = boost::is_integral<T>::value /* && <other trait(s)> */}; 
}; 

template< typename T, class Condition = DefaultCondition<T> > class Select 
{ 
    template<bool PassByValue = Condition::value, class Dummy = void> struct Resolve 
    { 
    typedef T type; 
    }; 

    template<class Dummy> struct Resolve<false, Dummy> 
    { 
    typedef const T& type; 
    }; 

    public: typedef typename Resolve<>::type type; 
}; 

Utilisation typique:

template<typename T> class EnterpriseyObject 
{ 
    typedef typename Select<T>::type type; 

    public: explicit EnterpriseyObject(type) 
    { 
    // ... 
    } 
}; 

struct CustomType {}; 

void Usage() 
{ 
    EnterpriseyObject<int>(0); // Pass-by-value. 
    (EnterpriseyObject<CustomType>(CustomType())); // Pass-by-const-reference. 
} 

Ceci, bien sûr, rompt indirectement déduction argument de modèle implicite de non-classe modèles:

template<typename T> void Foo(typename Select<T>::type) 
{ 
    // ... 
} 

void Usage() 
{ 
    Foo(0);  // Incomplete. 
    Foo<int>(0); // Fine. 
} 

Cela peut être "fixe" avec la bibliothèque Boost.Typeof et une macro, à la la WinAPI:

#define Foo(Arg) ::Foo<BOOST_TYPEOF((Arg))>((Arg)) 

Bien que ce soit juste un hack quasi-portable.

Comme vous pouvez le voir, mon approche générale n'est pas vraiment satisfaisante dans tous les cas. En tant que programmeur amateur, je n'ai ni l'expérience du monde réel ni l'accès au code de qualité de production pour référence. Je me rends compte aussi que cela peut sembler un mauvais cas d'optimisation prématurée, mais je suis vraiment intéressé par deux choses:

  1. -vous, ou avez-vous utilisé ce type d'optimisation * dans le passé?
  2. Est-ce que la bibliothèque Boost (ou toute autre bibliothèque publique) offre déjà des fonctionnalités similaires?
  3. Si la réponse à # 1 ou # 2 est un 'oui' - comment le cas du modèle hors classe est-il traité?
  4. Y a-t-il des pièges évidents que je ne vois pas avec quelque chose comme ça?
  5. Enfin, est-ce encore une chose saine à faire?

* Non profilé. ;)

+1

allait mentionner http://www.boost.org/doc/libs/1_43_0/doc/html/ref.html – 5ound

+0

@ 5ound: Aussi utile, merci! – chrosph

Répondre

2
  1. Oui. Tout le temps. Je l'utilise moi-même.
  2. Oui, utiliser Boost.Utility's Call Traits :)

    utilisation serait ...

    template <typename T> 
    void foo(boost::call_traits<T>::param_type param) 
    { 
        // Use param 
    } 
    
  3. Pour autant que je sache, les modèles non-classe sont passés par valeur à moins qu'il est plus rapide de ne pas. Grâce à la spécialisation partielle du modèle, il peut être personnalisé relativement facilement.

  4. Désolé, je n'ai pas vraiment lu ce que vous avez fait, il ressemblait exactement à ce que j'ai vécu il y a quelques mois. Par conséquent, je ne peux pas vraiment répondre à celui-ci. Ma recommandation est juste de lire Boost.Utility.

  5. Bien sûr!

+0

Excellent. Aurait dû regarder plus fort avant de poster. Merci beaucoup! ;) – chrosph

Questions connexes