Question

Considérez l'exemple minimal suivant qui reproduit un problème dans un projet beaucoup plus grand:

SPEC.H:
#include <iostream>

class A
{
public:
    template<typename T>
    T test(const std::string& a)
    {
        std::cout << "DEFAULT CALLED WITH " << a << "\n";
        return T();
    }
};

Autres.cpp:
#include "spec.h"

template<>
float A::test<float>(const std::string& a)
{
    std::cout << "SPECIAL CALLED WITH " << a << "\n";
    return float();
}

SPEC.CPP:
#include <iostream>
#include "spec.h"

int main()
{
    A a;
    a.test<int>("int");
    a.test<float>("float");
    return 0;
}

Compilation:
$ make
rm -f *.o lib.a output
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
ar cr lib.a other.o
clang++ -g -o output lib.a spec.o
rm -f *.o output2
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
clang++ -g -o output2 other.o spec.o

$ ./output
DEFAULT CALLED WITH int
DEFAULT CALLED WITH float

$ ./output2
DEFAULT CALLED WITH int
SPECIAL CALLED WITH float

Question:

Pourquoi cela se produit-il?Est-ce que ça se dépouille d'une manière ou d'une autre?Quelle est la différence entre la liberme et l'utilisation du fichier d'objet direct?: -)

merci!

Était-ce utile?

La solution

à partir de la section 14.7.3P6:

Si un modèle, un modèle de membre ou un membre d'un modèle de classe est explicitement spécialisé, alors que la spécialisation est déclarée avant la première utilisation de cette spécialisation qui entraînerait une instanciation implicite à avoir lieu, dans chaque unité de traduction dans lequel une telle utilisation survient ; aucun diagnostic n'est requis. Si le programme ne fournit pas de définition d'une spécialisation explicite et que la spécialisation est utilisée de manière à ce que l'instanciation implicite ait lieu ou que le membre est une fonction de membre virtuel, le programme est mal formé, aucun diagnostic requis.

Votre programme est mal formé car vous avez utilisé la spécialisation dans SPEC.CPP sans la déclarer en premier dans cette unité de traduction. Ou, comme indique le paragraphe suivant:

Le placement des déclarations de spécialisation explicites pour les modèles de fonctions, les modèles de classe, les fonctions des membres des modèles de classe, les éléments de données statiques des modèles de classe, les classes de classes de modèles de classe, les énumérations de membres de modèles de classe, les modèles de classes de classes de classes Modèles de modèles de classe, fonctions de membre des modèles de membres de modèles de classe, fonctions de membre des modèles de membres de classes non-Modèles, modèles de fonctions de membre de classes d'éléments de modèles de classe, etc., et la mise en place de déclarations de spécialisation partielles de modèles de classe, membre Modèles de classes de classes non-modèles, modèles de classes de membres de classes, etc., peut affecter si un programme est bien formé en fonction du positionnement relatif des déclarations de spécialisation explicites et de leurs points d'instanciation dans l'unité de traduction comme indiqué ci-dessus et ci-dessous.

Lorsque vous écrivez une spécialisation
Soyez prudent de son emplacement;
ou pour le faire compiler

sera un tel essai

que je vote pour comme le paragraphe Limerick dans toute la norme .

Autres conseils

La réponse de Ben Voigt est correcte, mais je veux y ajouter un peu.

Vous obtenez essentiellement deux versions différentes de la fonction, une dans une autre.o et une dans SPEC.O (générée par le modèle inline).La liaison est conçue pour choisir une seule et une seule, en prenant en charge qu'ils sont identiques à la fois identiques que la norme nécessite.Dans le premier cas, la liaison ne tirera qu'une définition d'une bibliothèque si le symbole n'est pas déjà défini.Comme il est défini dans SPEC.O La définition de la bibliothèque n'est pas utilisée.

Avec la définition dans l'en-tête, chaque unité de traduction peut créer sa propre instanciation.Ainsi, il n'y a jamais un symbole non défini qui fait référence à votre version spécialisée.De manière correspondante, le fichier d'objet avec la version spécialisée n'est pas inclus lors de la recherche sur la bibliothèque: elle ne définit aucun symbole non défini.Lorsque vous y compris le fichier d'objet explicitement, lors de la liaison, le linker n'a pas d'autre choix que celui-ci.Cependant, vous devez déclarer toutes les spécialisations: sans la déclaration, le compilateur n'a aucune idée que la version générale n'est pas applicable.Que se passe-t-il cette version, qu'elle soit utilisée ou non, dépend donc de la manière dont le symbole est traité.

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