9
votes

Est-il sécuritaire de placer la définition de la spécialisation de la fonction de modèle de modèle (sans organisme par défaut) dans le fichier source?

Voici ce que je veux dire: xxx

- xxx

- xxx

C'est complètement bien, non?

J'ai commencé à douter cela, car je viens de courir sur la spécialisation après l'instanciation erreur, qui était nouvelle pour moi. Donc, j'ai "travaillé autour de" cette erreur et tout semble fonctionner bien maintenant, mais toujours ..

est ce comportement bien défini?


edit: et le même pour les fonctions de modèle non membres (fonctions de modèle non membre non membre déclarées).


6 commentaires

Ah, je suis désolé. J'ai mal compris la question


Voir Cette question et y répondre.


Quel compilateur utilisez-vous? Comme je me souviens que je me souvienne de VC ++ enfreint l'exigence de la norme qui est notée dans [Temp.expl.spec] 14.7.3 / 6 et a été citée par @lighness races en orbite.


@Constructeur - GCC 4.4.5


@Kirilkirov essayez une nouvelle version de celui-ci. Les dernières versions de GCC sont plus conformes à la normalisation.


@Constructor - Oui, je vais essayer quand je peux, comme ici, je ne peux pas utiliser une version différente. Merci pour la référence à l'autre question aussi.


3 Réponses :


5
votes

Non, je ne pense pas que ça va:

[C ++ 11: 14/6]: Un modèle de fonction, une fonction de membre d'un modèle de classe ou un élément de données statique d'un modèle de classe doit être défini dans chaque unité de traduction dans laquelle elle est implicitement instancié (14.7.1) à moins que la spécialisation correspondante soit explicitement instanciée (14.7.2) dans une unité de traduction; Aucun diagnostic n'est requis.

[C ++ 11: 14.7.3 / 6]: Si un modèle, un modèle de membre ou un membre d'un modèle de classe est explicitement spécialisé, cette spécialisation doit être déclarée avant la première utilisation de cette spécialisation qui causerait une instanciation implicite à avoir lieu, dans chaque unité de traduction dans laquelle une telle utilisation se produit; Aucun diagnostic n'est requis. [..]

Franchement, je ne peux pas expliquer pourquoi cela fonctionne pour vous.


17 commentaires

"Franchement, je ne peux pas expliquer pourquoi cela fonctionne pour vous." Bien il y a un certain symbole Void CLS :: F (Const Char *) avec une liaison externe dans l'autre tu. Donc le symbole peut être trouvé . IIRC vous pouvez utiliser des modèles de fonctions déclarés, mais non définis (comme des fonctions normales); Vous pouvez fournir la définition après l'appel dans le même TU.


Qu'est-ce que modèle <> vide CLS :: f (const char *) {} sinon une instanciation explicite?


@ R.martinhofernandes: ah, les spécialisations explicites fonctionnent aussi aussi des instanciations explicites?


Je pense que: voir 14,7, paragraphe 4. Mais le libellé semble un peu déroutant.


@ R.martinhofernandes: Je pense que j'ai lu ce passage différemment.


Non attends. 14.7.2. définit clairement la "instanciation explicite". ARGH, je déteste ce style de description pleine de choses définies en avant :(


HM, je suis plus confus que le début. Mais ce que je pense, c'est la même chose que ce que @Dyp a écrit. Et comme il n'y a pas de corps par défaut pour cette fonction, il n'y a aucune chance d'exécuter la mauvaise fonction. Je veux dire - de là était une implémentation "par défaut" et spécialisation quelque part sinon - alors oui, cela pourrait être ambigu et pourrait conduire à un peu d'imprévue / résultats aléatoires. Mais dans ce cas, une telle erreur ne peut être faite. Alors, enfin?


BTW, avez-vous envisagé ce que 14.7.1 indique que des choses ne sont "implicitement instanciées" si elles sont utilisées dans un contexte nécessitant un type d'objet entièrement défini / une définition? Je pense qu'il n'y a pas d'instanciation implicite dans cet exemple: vous pouvez utiliser des fonctions sans leur définition. Cela fonctionne car le compilateur émet simplement le code d'objet «Call Indéfini» normal, puis le linker trouve ce symbole dans l'autre TU. ID est, il ne se comporte pas beaucoup différent des appels de fonction normaux lorsque seule une déclaration est présente.


@Kirilkirov Notez que je ne dis pas que c'est sûr (comportement bien défini), je devine simplement pourquoi sa fonctionne dans ce cas spécifique + mise en œuvre.


@Dyp - absolument. J'ai noté que, je viens de mentionner que mon explication est la même.


@ R.martinhofernandes n'est-il pas le "contexte qui nécessite une définition de fonction qui existe" se réfère à l'ODR? Cela ne dit pas que la définition doit exister dans le même tu.


Oh, bon point. Dammit, la norme semble impénétrable pour moi aujourd'hui. Je vais juste me taire.


Cela mène à la question suivante: qu'est-ce que est l'instanciation implicite d'un modèle de fonction? (Connecté: CWG Active Numéro 212 ) Est-ce que cela instancite uniquement la déclaration? La définition? Est-ce que cela dépend de quelque chose?


Le code de OP semble satisfaire aux parties de la norme que vous avez citées.


@Oktatalist Comment remplit-t-il la deuxième exigence (sur la déclaration de spécialisation explicite avant la première utilisation)? Comment le code dans main.cpp sera-t-il conscient de savoir que la spécialisation explicite du modèle principal est définie dans une autre unité de traduction?


@Constructeur Whoops, j'ai imaginé une partie du code de l'OP qui n'était pas vraiment là (une déclaration de la spécialisation explicite dans le fichier d'en-tête). C'est ce qui manque, bien sûr.


14.7.1 / 9 a l'air intéressant.



2
votes

Je pense que votre code d'origine était incorrect et que votre «contournement» n'est pas conforme à la normalisation, également (malgré le fait que votre compilateur et votre lieur traitent). Les bonnes citations de la norme ont été citées dans Répondre de @ Llighness races en orbite forte > . Voir aussi l'exemple suivant à partir de la norme ([Temp.expl.spec] 14.7.3 / 6):

class String { };
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }

void f(Array<String>& v) {
  sort(v);          // use primary template
                    // sort(Array<T>&), T is String
}

template<> void sort<String>(Array<String>& v); // error: specialization
                                                // after use of primary template
template<> void sort<>(Array<char*>& v);        // OK: sort<char*> not yet used


0 commentaires

6
votes

Lightness Courses en orbite cité pourquoi ce n'est pas conforme em> pièces de la norme. Il pourrait y avoir des autres, dans les environs.

Je vais essayer d'expliquer en termes simples ce que signifie le verbiage standard, et j'espère que je l'obtiendrai correctement, et enfin expliquer les erreurs de liaison (ou l'absence d'erreur):

  1. Quel est le point d'instanciation? LI>
  2. Comment le compilateur sélectionne-t-il une spécialisation? LI>
  3. Qu'est-ce qui est nécessaire au point d'instanciation? LI>
  4. Pourquoi une erreur de liaison? LI> ol>

    1 / Quel est le point d'instanciation? strong> p>

    Le point d'instanciation d'une fonction de modèle est le point où il est appelé ou référé to ( & std :: trier code>) avec tous em> les paramètres de modèle de modèle (*). p>

    template<>
    void cls::f( const char* )
    {
    }
    


0 commentaires