2017-02-03 4 views
1

Hier ist meine vereinfachte Testcode:Infinite Template-Instantiierung

struct Test { 
    Test() { run(0); } 

    template<class T> 
    static auto run(T&&, bool stop = false) -> void { if (!stop) _run<T>(); } 
    template<class R> 
    static auto _run() -> void { []() { run([]() {}, true); }(); } 
}; 

Wenn ich diesen Code mit GCC und Klirren zusammengestellt, es Kompilierungsfehler gibt:

/media/data/caca3d/src/b0util/test/tst_promise.cpp:30: error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) 
static auto _run() -> void { []() { run([]() {}, true); }(); } 
             ~~~^~~~~~~~~~~~~~~~ 

Ich kann nicht sehen, warum dieser Code Ursachen unendliche Template Instanziierung.

FYI, wenn ich template<class R> in _run() Funktion entfernen, sind die Fehler verschwunden.

Ich fand diesen Fehler, wenn ich etwas faule Auswertung mit Lambda-Funktion versuche, so kann ich indirekten Aufruf in Lambda nicht entfernen. Wie kann ich dieses Problem beheben?

+0

Benötigen Sie _run wirklich, um eine Vorlage zu sein? – SingerOfTheFall

+0

Ja. Dieser Code wird nur für den Test vereinfacht. Der tatsächliche Code verwendet die Metaprogrammierung von Vorlagen und Vorlagen stark. – xylosper

+0

ok, danke für die Erstellung des MCVE dann =) – SingerOfTheFall

Antwort

1

Schauen wir uns genauer an, was passiert. Die erste Funktion ruft explizit eine Vorlagenversion von _run() auf, ich nehme an, Sie haben keine Fragen zu diesem Teil.

template<class T> 
static auto run(T&&, bool stop = false) -> void { if (!stop) _run<T>(); } 

Die zweite ist interessanter. Es mag scheinen, dass es nur einmal instanziiert wird (da Sie run() nur einmal mit einem Lambda aufrufen), aber jedes Lambda, nach dem Standard, hat seinen eigenen einzigartigen Typ, so dass jedes Mal, wenn _run() instanziiert wird, die Erstellung von eine neue Version von run() (seit T wird von der Argumentart der Funktion abgeleitet), Erstellen einer Endlosschleife.

template<class R> 
static auto _run() -> void { []() { run([]() {}, true); }(); } 

Der einfachste Weg, um dieses Problem in diesem besonderen Beispiel run() nimmt ein std::function ein bestimmten (vielleicht Template-Parameter abhängig) wäre zu lösen, um geben, dass Ihr Lambda entspricht.

+0

Danke für die schnelle und klare Antwort. Vielleicht werde ich versuchen, std :: function zu verwenden, die endliche instanziierte Typen anstelle von Lambda hat. Danke vielmals. – xylosper

+0

@xylosper, yep, das ist genau das, was ich vorschlagen würde =) – SingerOfTheFall

+0

@xylosper, übrigens (nicht sicher, ob Sie es wirklich brauchen, aber es ist ein nettes Feature), können Sie 'std :: function' machen s basierend auf Parameterpaketen, zum Beispiel 'template Klasse function_wrapper {public: std :: function functionPointer};' – SingerOfTheFall