2011-09-10 10 views
22

Si consideri l'esempio che ho trovato sul sito di IBM:GCC, Clang e IBM non sono d'accordo su come eseguire la ricerca del nome dipendente dal modello. Quale è giusto?

#include <iostream> 
using namespace std; 

void f(double) { cout << "Function f(double)" << endl; } 

template<class T> void g(T a) { 
    f(123); 
    h(a); 
} 

void f(int) { cout << "Function f(int)" << endl; } 
void h(double) { cout << "Function h(double)" << endl; } 

void i() { 
    extern void h(int); 
    g<int>(234); 
} 

void h(int) { cout << "Function h(int)" << endl; } 

int main(void) { 
    i(); 
} 

Che cosa ci stampare?

  • La documentazione IBM mi sono adattato questo esempio da, disponibili here, dice che la stampa:

    Function f(double) 
    Function h(double) 
    

    La logica di questo è che il nome del modello-parametro dipendente dalla ricerca viene eseguita a destra prima l'istanza di i(), quindi trova h(double) ma non h(int).

  • Quando compilo usando GCC 4.4.1, esso stampa:

    Function f(double) 
    Function h(int) 
    

    GCC sembra essere alla ricerca i nomi modello-parametri-dipendente nel modello dopo tutto il resto è stato compilato, in modo da trova sia h(double) e h(int), e preferisce quest'ultimo.

  • Quando compilo usando Clang 2.8, non riesce a compilare. L'errore del compilatore è:

    ibm_example.cc:8:3: error: use of undeclared identifier 'h' 
        h(a); 
    ^
    ibm_example.cc:16:3: note: in instantiation of function template specialization 'g<int>' requested here 
        g<int>(234); 
    ^
    1 error generated. 
    

    Clang sembra essere alla ricerca i nomi modello-parametri-dipendente nel modello nel punto in cui viene dichiarato il modello, in modo da non trova né h(double)h(int).

Quale è giusto?

+0

possibile duplicato di [? Quali sono le regole per la scelta di funzioni template sovraccarico] (http://stackoverflow.com/questions/1177739/what-are -le-regole-per-scegliere-da-funzioni-modello-sovraccarico) –

+0

Nessuna modifica per GCC 4.5.1 FWIW. – ergosys

+1

@Foo: Questo non è assolutamente un duplicato di quella domanda, che riguarda la risoluzione di sovraccarico, questa riguarda l'ambito e quali simboli sono visibili al punto di definizione. – ildjarn

risposta

13

Sono tutti corretti. No davvero, continuate a leggere ...

template<class T> void g(T a) { 
    f(123); 
    h(a); 
} 

Qui, f è un nome non-dipendente, ma h è un nome dipendente secondo la 14.6.2/1. f viene cercata

nomi non-dipendenti impiegati in una definizione di modello si trovano utilizzando la solita ricerca del nome e legato al punto vengono utilizzati.

f viene cercato immediatamente e legato alla void f(double), l'unico f visibile in quel punto.

In base al 14.6.4.1 il punto di istanziazione di void g<int>(int) è immediatamente dopo la definizione di void i(), dove viene utilizzato.

[..] In caso contrario, il punto di istanziazione per tale specializzazione segue immediatamente la dichiarazione ambito namespace o definizione che si riferisce alla specializzazione.

Ciò significa che le fonti per risolvere il nome dipendente sono visibili dichiarazioni alla definizione di template<class T> void g(T a) e "dichiarazioni di namespace associate ai tipi dei parametri funzionali sia dal contesto istanziazione (14.6.4.1) e dalla definizione contesto "(14.6.4).

Tuttavia, poiché int è un tipo fundemantal, l'insieme dei namespace associato è vuoto (3.4.2) (senza nemmeno il namespace globale è incluso) e secondo 14.6.4.2 è occhiata solo utilizzando i namespace associate che può utilizzare il contesto di istanziazione del modello, la ricerca normale del nome non qualificato può utilizzare solo ciò che è visibile nel contesto di definizione del modello. Ciò conferma ciò che è stato detto in 14.6.4.

Ora, il punto bonus. 14.6.4.2 continua a dire:

Se la chiamata sarebbe mal formata o avrebbe trovato una migliore corrispondenza ha avuto la ricerca all'interno dei namespace associati considerate tutte le dichiarazioni di funzione con collegamento esterno introdotta in tali spazi dei nomi in tutte le traduzioni unità, non considerando solo quelle dichiarazioni trovate nella definizione del modello e nei contesti di istanziazione del modello, allora il programma ha un comportamento indefinito.

La chiamata è mal formate a causa di ricerca fallisce (la parte sugli spazi dei nomi associati non si applica qui), in modo che il comportamento è esplicitamente definito quindi tutto può succedere. Quindi nessuno dei comportamenti visti mostra una non conformità allo standard sebbene, a mio avviso, la diagnostica di Clang sembri più in linea con lo standard.

(Tutti i riferimenti ISO/IEC 14882: 2011.)

+0

Si può interpretare la parte relativa al comportamento non definito con un'associazione diversa, che sembra avere più senso per me: "Se {{la chiamata sarebbe mal formata} o {trovare una corrispondenza migliore} ha avuto la ricerca all'interno di spazi dei nomi associati considerati tutte le dichiarazioni di funzioni con collegamento esterno introdotte in quegli spazi dei nomi in tutte le unità di traduzione}, ... quindi il programma ha un comportamento non definito ". –

+0

O formulato in modo diverso (parte successiva del paragrafo "Se {{la chiamata sarebbe mal formata} o {troverebbe una corrispondenza migliore} la ricerca all'interno di spazi dei nomi associati non ha considerato solo quelle dichiarazioni trovate nella definizione del modello e nei contesti di istanziazione del modello }, quindi il programma ha un comportamento indefinito. " –

+0

Questa associazione ha più senso per me perché il compilatore (a differenza del linker) non può guardare più unità di traduzione, quindi lo standard non richiede una diagnostica per quei casi in cui l'implementazione farebbe così, la chiamata sarebbe ambigua/mal formata o trovare una corrispondenza migliore. –

Problemi correlati