2016-06-16 10 views
3

Angenommen, ich einen Header wrapper.h haben:Ist es möglich, Vorlage explizit zu labda zu spezialisieren?

template <typename Func> void wrapper(const Func func); 

und eine Datei wrapper.cpp enthält:

#include "wrapper.h" 
template <typename Func> 
void wrapper(const Func func) 
{ 
    func(); 
} 

Und eine Datei main.cpp enthält:

#include "wrapper.h" 
#include <iostream> 

int main() 
{ 
    wrapper([](){std::cout<<"hello."<<std::endl;}); 
} 

Wenn ich diese zusammen kompilieren (zB cat wrapper.cpp main.cpp | g++ -std=c++11 -o main -x c++ -), bekomme ich keinen Linker e Richtig.

Aber wenn ich sie separat kompilieren (zB g++ -std=c++11 -o wrapper.o -c wrapper.cpp && g++ -std=c++11 -o main main.cpp wrapper.o), I --- --- natürlich einen Linker Fehler:

Undefined symbols for architecture x86_64: 
    "void wrapper<main::$_0>(main::$_0)", referenced from: 
     _main in main-5f3a90.o 

Normalerweise könnte ich ausdrücklich wrapper spezialisieren und so etwas wie dies in den wrapper.cpp:

template void wrapper<void(*)()>(void(*)()) 

Aber diese spezielle Template-Spezialisierung funktioniert nicht.

Ist es möglich, eine Vorlage auf einem Lambda zu spezialisieren?

+1

Sie könnten das Lambda immer in diesen Funktionszeiger konvertieren. – chris

+4

Da der Vorlagencode in einer 'cpp'-Datei enthalten ist, meintest du _explicit template instanziation_? –

+2

'Vorlage void wrapper (void (*)())' ist ** explizite Instanziierung ** nicht ** Spezialisierung **, wie Sie es nennen. Es gibt einen [Unterschied] (http://stackoverflow.com/a/4933205/1621391) zwischen den beiden – WhiZTiM

Antwort

9

Erstens, ich nehme an, Sie wissen über Why can templates only be implemented in the header file?

Um Ihre Frage:

Is it possible to specialize a template on a lambda?

Leider mit genauem Spiel Nein, Template Spezialisierungen arbeiten und ein lambda ist eine einzigartige unbenannte Art. Das Problem ist spezialisiert auf den Typ, den Sie nicht kennen.

Ihre beste Wette ist zu verwenden std::function; oder, wie Sie getan haben, dann zwingt zusätzlich das Lambda in einen Funktionszeiger umgewandelt wird durch +

int main() 
{ 
    wrapper(+[](){std::cout<<"hello."<<std::endl;}); 
} 

Voll Beispiel Zugabe:

#include <iostream> 

template <typename Func> 
void wrapper(const Func func) 
{ 
    std::cout << "PRIMARY\n"; 
    func(); 
} 

template <> 
void wrapper<void(*)()>(void(*func)()) 
{ 
    std::cout << "SPECIALIZATION\n"; 
    func(); 
} 

int main() 
{ 
    wrapper([](){std::cout<<"hello\n"<<std::endl;}); 
    wrapper(+[](){std::cout<<"world."<<std::endl;}); 
} 

Dieser Druck wird

PRIMARY 
hello 

SPECIALIZATION 
world 

Auch decltype Einrichtung würde nicht helfen, if it does, wird es wegnehmen die Flexibilität von Ihrem Bedarf für Lambda

0

Leider können Sie nicht.

Ihr Problem ist, dass Lambdatypen innerhalb jeder Kompilierungseinheit zufällig generiert werden.

Sie können Funktionen über Einheiten hinweg verwenden, da Sie sie in Headern deklarieren können; dann findet der Linker denjenigen mit dem richtigen Namen und gibt die Kompilierungseinheit ein, die ihn definiert. Gleiches, wenn Sie eine Variable deklarieren, jedoch weniger häufig. Wenn die Deklaration in jeder Einheit zu einem anderen Typ führt, würde dies fehlschlagen und keine Interaktion zwischen Einheiten wäre möglich.

Wenn Sie also versuchen, das Lambda als "dasselbe" Objekt in den beiden Einheiten zu definieren (d. H. Im Header definieren), schlägt die Verknüpfung fehl, weil Sie das gleiche Objekt nicht zweimal definieren können. Und wenn Sie sie zu "verschiedenen" Objekten machen (d. H. Hinzufügen inline oder in der Quelle definieren), werden sie unterschiedliche Typen haben, so dass die Verlinkung sie nicht so zusammenführen kann, wie Sie es brauchen würden. Kann nicht gewinnen.

0

anhören: Why can templates only be implemented in the header file?

Als Template-Definition aus der Datei wrapper.cpp in Headerdatei wrapper.h bewegt wird, die Hülle() kann durch die vorgeschlagenen Wege in main.cpp aufgerufen werden:

int main() 
{ 
    wrapper([](){std::cout<<"hello"<<std::endl;}); 
    wrapper(+[](){std::cout<<"world"<<std::endl;}); 
    wrapper(std::function<void()>([](){std::cout<<"best"<<std::endl;})); 
} 
Verwandte Themen