web-dev-qa-db-fra.com

Constructeur de template C ++

Je souhaite avoir une classe non-template avec un constructeur de template sans arguments.

Autant que je sache, il est impossible de l'avoir (car cela entrerait en conflit avec le constructeur par défaut - c'est vrai?), et la solution de contournement est la suivante:

class A{
   template <typename U> A(U* dummy) {
   // Do something
   }
};

Peut-être qu'il y a une meilleure alternative pour ceci (ou une meilleure solution de contournement)?

104
Yippie-Ki-Yay

Il n’existe aucun moyen de spécifier explicitement les arguments du modèle lors de l’appel d’un modèle de constructeur. Ils doivent donc être déduits par déduction d’argument. C'est parce que si vous dites:

Foo<int> f = Foo<int>();

Le <int> est la liste des arguments de modèle pour le type Foo, pas pour son constructeur. Il n'y a nulle part où aller pour la liste d'arguments du modèle de constructeur.

Même avec votre solution de contournement, vous devez toujours passer un argument pour appeler ce modèle de constructeur. Ce que vous essayez d'accomplir n'est pas du tout clair.

94
James McNellis

Vous pouvez créer une fonction d'usine basée sur un modèle:

class Foo
{
public:
    template <class T> static Foo* create() // could also return by value, or a smart pointer
    {
        return new Foo(...);
    }
...        
};
32
KeatsPeeks

Autant que je sache, il est impossible de l'avoir (car cela entrerait en conflit avec le constructeur par défaut - ai-je raison?)

Vous avez tort. Cela ne crée aucun conflit. Vous ne pouvez pas l'appeler jamais.

23
template<class...>struct types{using type=types;};
template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;

les aides ci-dessus vous permettent de travailler avec des types en tant que valeurs.

class A {
  template<class T>
  A( tag<T> );
};

le tag<T> type est une variable sans état autre que le type carie. Vous pouvez l'utiliser pour passer une valeur de type pur à une fonction de modèle et en déduire le type à l'aide de la fonction de modèle:

auto a = A(tag<int>{});

Vous pouvez passer dans plus d'un type:

class A {
  template<class T, class U, class V>
  A( types<T,U,V> );
};
auto a = A(types<int,double,std::string>{});
16

Des points:

  • Si vous déclarez un constructeur tout (y compris un constructeur basé sur un modèle), le compilateur s'abstiendra de déclarer un constructeur par défaut.
  • A moins que vous ne déclariez un constructeur de copie (pour la classe X, celui qui prend X ou X& ou X const &) le compilateur générera le constructeur de copie par défaut.
  • Si vous fournissez un constructeur de modèle pour la classe X, qui prend T const & ou T ou T& _ alors le compilateur générera néanmoins un constructeur de copie par défaut sans modèle, même si vous pensez peut-être que cela ne devrait pas car, lorsque T = X, la déclaration correspond à la déclaration du constructeur de copie.
  • Dans ce dernier cas, vous pouvez vouloir fournir un constructeur de copie non basé sur un modèle avec celui basé sur un modèle. Ils ne seront pas en conflit. Lorsque X est passé, le non-modèle sera appelé. Sinon le modèle

HTH

15
Armen Tsirunyan

Vous pourriez faire ceci:

class C 
{
public:
    template <typename T> C(T*);
};
template <typename T> T* UseType() 
{
    static_cast<T*>(nullptr);
}

Ensuite, pour créer un objet de type C, utilisez int comme paramètre de modèle du constructeur:

C obj(UseType<int>());

Comme vous ne pouvez pas transmettre de paramètres de modèle à un constructeur, cette solution convertit essentiellement le paramètre de modèle en paramètre standard. L'utilisation de la fonction UseType<T>() lors de l'appel du constructeur indique clairement à ceux qui consultent le code que l'objectif de ce paramètre est d'indiquer au constructeur le type à utiliser.

Un cas d'utilisation pour cela serait si le constructeur crée un objet de classe dérivée et l'assigne à une variable membre qui est un pointeur de classe de base. (Le constructeur doit savoir quelle classe dérivée utiliser, mais la classe elle-même n'a pas besoin d'être basée sur un modèle, car le même type de pointeur de classe est toujours utilisé.)

2
Tolli

essayez de faire quelque chose comme

template<class T, int i> class A{

    A(){
          A(this)
    }

    A( A<int, 1>* a){
          //do something
    }
    A( A<float, 1>* a){
         //do something
    }
.
.
.
};
0
user2616927

Voici une solution de contournement.

Créez un sous-type de modèle B sur A. Créez la partie indépendante de la construction du modèle dans le constructeur de A. Effectuer la partie dépendante du modèle-argument dans le constructeur de B.

0
Syncopated