2013-08-31 11 views
5

Ho una dichiarazione anticipata di una classe template in un namespace nidificatoDichiarazione anticipata della classe template nello spazio dei nomi annidato: dove dovrebbero andare gli argomenti del modello predefinito?

namespace n1 
{ 
    namespace n2 
    { 
     template <typename T, typename S> 
     struct A; 
    } 
    using n2::A; 
} 

seguita da una definizione, che in realtà è in un file diverso, con roba in mezzo:

struct X { }; 

namespace n1 
{ 
    namespace n2 
    { 
     template <typename T, typename S = X> 
     struct A { }; 
    } 
    using n2::A; 
} 

Poi il segue è sempre ok:

n1::n2::A <int> a; 

ma questa scorciatoia

n1::A <int> a; 

dà un errore di compilazione in clang

error: too few template arguments for class template 'A' 

a meno che non posso rimuovere la dichiarazione anticipata; g ++ accetta entrambi.

clang sembra rimanere con la prima dichiarazione che non include l'argomento del modello predefinito (e non posso includerlo, perché non ho ancora definito X).

Non c'è alcun problema se utilizzo un singolo spazio dei nomi (ma questa non è una soluzione).

Cosa sto facendo male, o quale compilatore è corretto? In che modo la scorciatoia può funzionare insieme alla dichiarazione in avanti e allo spazio dei nomi annidato? Ho bisogno di tutti loro.

Inoltro in avanti X + argomento predefinito per S ovviamente funziona, ma sarebbe troppo noioso (ce ne sono in realtà dozzine e l'intera struttura del file cambierebbe).

+0

Il fatto che ci siano elementi in mezzo e che si trovano in un file diverso non ha importanza per il clang. [Esempio dal vivo] (http://coliru.stacked-crooked.com/view?id=fd521dbdf5) – dyp

+0

E secondo [temp.param]/10, questo problema non è correlato ai modelli, poiché il meccanismo è definito in termini di argomenti di default della funzione. [Esempio dal vivo] (http://coliru.stacked-crooked.com/view?id=17873283ec) – dyp

+0

Questo potrebbe essere un po 'più complicato di quanto pensassi in origine. [dcl.fct.default]/9 in realtà dice che il tuo codice dovrebbe funzionare, ma c'è un [problema aperto] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1551) con * using-declaration * dove la correzione proposta introduce una contraddizione in questo paragrafo e potrebbe infrangere il codice. – dyp

risposta

1

Ho trovato questo come una soluzione più conveniente:

namespace n1 
{ 
    namespace n2 
    { 
     template <typename T, typename S> 
     struct A; 
    } 

    namespace fwd { using n2::A; } 
} 

// stuff on n1::fwd::A; 

struct X { }; 

namespace n1 
{ 
    namespace n2 
    { 
     template <typename T, typename S = X> 
     struct A { }; 
    } 

    using n2::A; 
} 

Cioè, spostare la prima dichiarazione using a un altro spazio dei nomi. Ora la 'roba' potrebbe andare in questo modo:

namespace n1 
{ 
    namespace stuff 
    { 
     using namespace fwd; 

     template <typename T> 
     struct R /*...*/; 

     template <typename T, typename S> 
     struct R <A <T, S> > /*...*/; 
    } 
} 

utilizzando A senza alcun namespace. C'è solo uno n1 nel mio progetto, ma un sacco di n2, quindi spostare tutte le dichiarazioni di utilizzo in avanti in un singolo spazio dei nomi n1::fwd è più conveniente, dato che non posso semplicemente usare n1.

2

template<class T> using myname = some::templatething<T>;

Quindi è possibile utilizzare mionome

Nel tuo caso attaccare un template<class T,class S=X> using A = n2::A<T,S>; nella vostra n1

appena scritto una gemma di una risposta relativa a questo Symbol not found when using template defined in a library lì btw, hanno un letto.

Ok, non è stato spuntato, quindi ho intenzione di aiutare un po 'di più!

non verrà compilato

#include <iostream> 

namespace n1 { 
namespace n2 { 
template<class U,class V> struct A; 
} 
template<class U,class V> using A = n2::A<U,V>; 
} 

static n1::A<int,int>* test; 

struct X {}; 
namespace n1 { 
namespace n2 { 
template<class U,class V> struct A {}; 
} 
template<class U,class V=X> using A = n2::A<U,V>; 
} 

static n1::A<int> test2; 


int main(int,char**) { 

    return 0; 
} 

Perché? 'Prima regola dichiarazione' C++ s '

Ecco l'output del compilatore:

make all 
if ! g++ -Isrc -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings -MM src/main.cpp >> build/main.o.d ; then rm build/main.o.d ; exit 1 ; fi 
g++ -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings -Isrc -c src/main.cpp -o build/main.o 
src/main.cpp:26:17: error: wrong number of template arguments (1, should be 2) 
static n1::A<int> test2; 
       ^
src/main.cpp:13:47: error: provided for ‘template<class U, class V> using A = n1::n2::A<U, V>’ 
template<class U,class V> using A = n2::A<U,V>; 
              ^
src/main.cpp:26:24: error: invalid type in declaration before ‘;’ token 
static n1::A<int> test2; 
         ^
src/main.cpp:16:24: warning: ‘test’ defined but not used [-Wunused-variable] 
static n1::A<int,int>* test; 
         ^
src/main.cpp:26:19: warning: ‘test2’ defined but not used [-Wunused-variable] 
static n1::A<int> test2; 
       ^
make: *** [build/main.o] Error 

Va bene che è piagnucolare sulle variabili non utilizzate, abbastanza giusto, ma notate è indicando la linea 13, che è perché ha usato la prima definizione argomenti di template di default sono davvero abbastanza primitivi e non posso citare le specifiche in questo momento. https://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fdefault_args_for_templ_params.htm

che può offrire qualche intuizione però.

In ogni caso notare che:

Questo compila

#include <iostream> 

namespace n1 { 
namespace n2 { 
template<class U,class V> struct A; 
} 
template<class U,class V> using A = n2::A<U,V>; 
} 

static n1::A<int,int>* test; 

struct X {}; 
namespace n1 { 
namespace n2 { 
template<class U,class V> struct A {}; 
} 
template<class U,class V=X> using B = n2::A<U,V>; 
} 

static n1::B<int> test2; 


int main(int,char**) { 

    return 0; 
} 

Poiché B non ha una definizione preventiva.

uscita Corporatura

make all 
if ! g++ -Isrc -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings -MM src/main.cpp >> build/main.o.d ; then rm build/main.o.d ; exit 1 ; fi 
g++ -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings -Isrc -c src/main.cpp -o build/main.o 
src/main.cpp:16:24: warning: ‘test’ defined but not used [-Wunused-variable] 
static n1::A<int,int>* test; 
         ^
src/main.cpp:26:19: warning: ‘test2’ defined but not used [-Wunused-variable] 
static n1::B<int> test2; 
       ^
g++ build/main.o -o a.out 

Sede, bene :)

ricordare con le dichiarazioni previsionali si possono utilizzare solo * s e & s (in quanto sono di dimensioni note, dimensioni infatti fisso) - oh e & & s

Quindi è necessario ottenere quel valore predefinito in là subito!

+0

Grazie, Questo evita di usare la vera A in n1 prima che sia completo, e usa un * nome * diverso per la dichiarazione d'uso; ma lo trovo troppo complicato. Per il momento, ho rimosso la forward-declaration e ho dichiarato "roba" dopo che A è stato completato, il che penso sia un design migliore. Se ne avessi davvero bisogno in futuro, e come ho scritto nel mio commento sotto la domanda, preferirei spostare la dichiarazione using in un altro spazio dei nomi piuttosto che rinominarlo, evitando così del tutto gli argomenti del template - Aggiungerò una risposta per quella. – iavr

+0

Questo problema è diverso dagli OP, poiché si utilizzano dichiarazioni di modelli alias ('modello < /*...*/ > usando X = /*...*/;') mentre l'OP utilizza dichiarazioni di alias "semplici" (non modello). Gli effetti sono diversi (sia clang ++ che g ++ lo rifiutano), e questo non ha niente a che fare con namespace -> [Esempio live] (http://coliru.stacked-crooked.com/view?id=b6f6a922c2) .Potrebbe avere a che fare con [open issue 1349] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1349). – dyp

Problemi correlati