Question

Je reçois une erreur de linker lors de l'utilisation d'un modèle de classe où j'ai essayé la mise en œuvre de l'idiome copier-échange comme le suggère ici:

Quel est l'idiome copier-échange?

La classe de modèle, appelons-le « TemplateClass » est partiellement défini comme ceci:

template< class T >
class TemplateClass
{
    // ...
    TemplateClass< T >& operator= ( TemplateClass< T > other );
    friend void swap( TemplateClass< T >& first, TemplateClass< T >& second );
    // ...
};

J'ai mis les mises en œuvre dans un TemplateClass.cpp séparé qui est inclus dans le fichier .h. (Edit: J'ai le même problème si tout est dans le fichier .h)

L'opérateur d'affectation est définie comme suit:

template< class T >
TemplateClass< T >& TemplateClass< T >::operator= ( TemplateClass< T > other )
{
    // copy-and-swap idiom
    swap( *this, other );
    return *this;
}

et le procédé d'échange est définie comme suit:

template< class T >
void swap( TemplateClass< T >& first, TemplateClass< T >& second )
{
    using namespace std;
    swap( first.member1, second.member1 );
    swap( first.member2, second.member2 );
    // ...
}

(Ne vous inquiétez pas, je ne nomme pas vraiment mes membres "member1" etc)

J'ai une classe similaire qui est définie de la même manière, mais pas une classe de modèle. Tout fonctionne très bien là-bas. Cependant, si j'ai un TestClass de classe qui a un membre TemplateClass< HandledClass > member et je fais un appel à l'une de ses méthodes comme

void TestClass::setMember( TemplateClass< HandledClass > newObject )
{
    member = newObject;
}

J'obtiens une erreur externe non résolu:

LNK2019: symbole externe non résolu "swap __cdecl vide (classe TemplateClass et, classe TemplateClass &)" (...) en fonction "publique: classe TemplateClass X & __thiscall TemplateClass opérateur X :: = (classe TemplateClass)" (. ..) dans TestClass.obj

Ou en d'autres termes: Quelque chose dans les appels TestClass TemplateClass<HandledClass>::operator= qui ne trouve pas void swap( TemplateClass<HandledClass>, TemplateClass<HandledClass> ).

Alors ma question est: Pourquoi l'opérateur trouve pas la méthode d'échange?

On dirait qu'il n'a pas été compilé pour l'argument de modèle. Est-il possible d'avoir en quelque sorte le compilateur vides de compilation ami aussi?

Je pourrais probablement fossé l'approche friend void et définir une méthode d'échange en classe plus une méthode d'échange hors-classe plus un espace de nom std, mais je ne sais pas si cela fonctionnerait de cette façon et je voudrais d'éviter que, si possible, de toute façon.


Solution:

a fait le travail:

template< class t >
class TemplateClass
{
    friend void swap( TemplateClass& first, TemplateClass& second )
    {
        // ...
    }
};

Notez comment je devais enlever le occurrences ainsi.

Était-ce utile?

La solution

Ceci est un problème commun quand lier d'amitié avec des fonctions non-membres avec des modèles. La déclaration de friend à l'intérieur du TemplateClass ne pas lier d'amitié avec votre modèle de swap, mais plutôt une swap fonction libre non basé sur un modèle qui prend TemplateClass<T> pour laquelle T jamais le modèle est instancié (la TemplateClass<int> de spécialisation lier d'amitié avec une void swap( TemplateClass<int>&,TemplateClass<int>& ); fonction libre qui ne templated).

La meilleure solution est de fournir la définition de swap inline dans la définition du modèle de classe, comme cela fera le compilateur génère une fonction de swap non pour le type basé sur un modèle exact à chaque fois que nécessaire. Comme un autre effet secondaire positif, cette fonction de swap ne se trouve au cours Argument de recherche dépendant, il ne prendra pas partie de la résolution de surcharge pour tout ce qui ne concerne pas votre modèle.

D'autres alternatives sont consolateur toute fonction de modèle de swap ou lier d'amitié avec la spécialisation particulière de la fonction swap lorsqu'elle est appliquée à la même T que le modèle a été instancié avec. La première des options est simple dans le code, mais il donne accès à tous des spécialisations du modèle de swap, et qui pourraient avoir des effets secondaires néfastes. Apprivoiser les résoud particulières de spécialisation swap que la question, mais il est un peu plus complexe à mettre en œuvre (vous devez déclarer avant le modèle de classe, le modèle de swap, définir le modèle de classe, et enfin définir le modèle de swap).

En savoir plus sur cette question dans cet autre réponse , où les différentes options et syntaxes sont expliqués avec plus de détails.

En ce qui concerne le message d'erreur particulière de unresolved external, qui est due à la façon dont l'identificateur de recherche fonctionne. Lorsque vous avez utilisé swap(*this,other); dans une fonction de membre, commence Lookup sein de la classe, et essaie de trouver un swap approprié. Il regarde d'abord dans le contexte de la classe et trouve la déclaration de la fonction friend libre, donc ne recherche continue pas aller vers l'extérieur et ajoute une dépendance à cette fonction libre particulière. Il ajoute la dépendance et attend l'éditeur de liens pour localiser le symbole approprié. Parce que le compilateur n'a jamais considéré le swap basé sur un modèle au niveau de l'espace de noms, il ne fait instancié, mais même si elle avait instancié ce modèle, la dépendance à l'intérieur de la fonction de membre de operator= est une fonction libre, pas que la spécialisation.

Autres conseils

Vous devriez soit mettre la déclaration de modèle de classe dans le fichier d'en-tête, ou si vous savez à l'avance tous les types que ce modèle de classe sera instanciée, fournir instanciation explicite au fichier d'en-tête:

template< class T >
class TemplateClass
{
    // ...
    TemplateClass< T >& operator= ( TemplateClass< T > other );
    friend void swap( TemplateClass< T >& first, TemplateClass< T >& second );
    // ...
};

template class TemplateClass<FirstType>;
template class TemplateClass<SecondType>;
// ...

// and the same for swap function
template void swap<FirstType>( TemplateClass<FirstType>& first, TemplateClass<FirstType>& second );
template void swap<SecondType>( TemplateClass<SecondType>& first, TemplateClass<SecondType>& second );

Il est fastidieux, mais il est parfois la meilleure option.

En ce qui concerne la raison pour laquelle votre échange ne lien: vous déclarez friendnes avec fonction swap non-modèle, qui ne exist.Try ceci:

template< class T >
class TemplateClass
{
    // ...
    TemplateClass< T >& operator= ( TemplateClass< T > other );
    template < class U > friend void swap( TemplateClass< U >& first, TemplateClass< U >& second );
    // ...
};

Des efforts supplémentaires nécessaires si vous voulez être un puriste et être que des amis avec votre 'swap (swap avec les mêmes paramètres de modèle).

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