Ricevo un comportamento coerente sia da gcc 4.8.3 che da clang 3.2, ma non capisco perché sta accadendo. Nonostante io abbia un'istanza esplicativa per un modello di classe, il codice non viene generato e ottengo un simbolo indefinito quando sto usando un'istanza completamente specializzata del modello.Nessun codice generato per modello esplicitamente specializzato anche con istanziazione esplicita
Ho una semplice definizione di modello di classe in un file 'temp.hpp'
#pragma once
template <typename T1>
class C
{
public:
C (T1 c) : d_c(c) {};
~C() = default;
void print();
private:
T1 d_c;
};
Nota che il 'print()' metodo è dichiarato, ma non definito qui. Voglio la definizione nel file .cpp e sarà specializzata per diversi tipi.
Così nel file temp.cpp ho la definizione di default del metodo di stampa()
#include "temp.hpp"
#include <iostream>
template<typename T1>
void
C<T1>::print()
{
std::cout << "Printing: " << d_c << std::endl;
}
seguita da una specializzazione della classe per il tipo 'float':
template <>
class C <float>
{
public:
C (float f) : d_f(f) {};
~C() = default;
void print()
{
std::cout << "float: " << d_f << std::endl;
}
private:
float d_f;
};
e poiché le definizioni sono nel file .cpp, devo esplicitare esplicitamente tutte le specializzazioni che userò. Così ho:
template class C<int>;
template class C<float>;
Il driver per il mio test si presenta così in test.cpp:
#include "temp.hpp"
int main()
{
int i = 1;
C<int> c_int(i);
float f = 1.2;
C<float> c_float(f);
c_int.print();
c_float.print();
}
Su compilazione e collegamento questo ottengo errore:
test.cpp: undefined reference to `C<float>::print()'
Il codice oggetto per C < int> è generato correttamente. Posso vedere usando nm:
nm -C temp.o
...
0000000000000000 W C<int>::print()
0000000000000000 W C<int>::C(int)
0000000000000000 W C<int>::C(int)
...
Come ho già detto in precedenza, questo è coerente con gcc e clang così sto assumendo c'è qualche regola di lingua che non capisco qui.
Si noti che se aggiungo un utilizzo del metodo print() nel file temp.cpp, il codice viene generato, ma quello è sciocco e nel mio codice reale sarebbe impossibile. Per questo semplice caso di test sarebbe simile:
void foo()
{
C<float> s(1.3);
s.print();
}
Nel codice vero e proprio, che ha motivato questo piccolo test il mio modello dispone di 3 argomenti di template che si combinano per espandersi in circa 30 permutazioni del codice. Ce ne sono uno o due per i quali ho bisogno di una specializzazione che faccia qualcosa di diverso, ma l'altro 28 posso lasciare da solo.
Qualsiasi suggerimento su dove ho sbagliato o un riferimento al linguaggio per il motivo per cui l'istanziazione esplicita di non dovrebbe generare codice è molto apprezzato. Ho passato 1/2 giorno a leggere tutti gli altri post StackOverflow su istanziazione esplicita e credo di usarlo correttamente.
modo da avere la specializzazione per '' C in 'temp.cpp', ma si desidera utilizzare che la specializzazione in' test.cpp'? Questo é un problema. Il tipo specializzato 'C ' è un tipo diverso e completamente indipendente da quello che si otterrebbe se si sostituisse 'float' per' T1' nel modello originale. In 'test.cpp', sta cercando' C :: print() 'dove' T1 == float', e questo non esiste nel tuo programma. Se sposti la specializzazione nell'header 'temp.hpp', allora dovrebbe funzionare; la specializzazione deve essere visibile al compilatore durante l'elaborazione di 'test.cpp'. –
Grazie per la spiegazione Jason, Nel codice reale la quantità di codice in specializzazione è sufficientemente complessa da disegnare in un mucchio di altri file di intestazione e finirei nell'intestazione Hades per scopi di compilazione. Ho trovato una soluzione alternativa in cui posso mantenere le espansioni che generano codice illecito più in alto nella gerarchia di espansione. – Jay