7

Ich schreibe eine Bibliothek mit vielen Funktionsobjekten, deren Klassen mehrere operator() Überladungen haben, die nicht vom Zustand der Klassen abhängen und es nicht ändern. Nun habe ich versucht, meinen Code mit vielen alten APIs arbeiten zu lassen (es ist keine zufällige Notwendigkeit, ich musste mich tatsächlich mit solchen APIs auseinandersetzen) und beschloss daher, die Funktionsobjekte in einen Funktionszeiger umzuwandeln, der einem der beiden entspricht Überladungen. Irgendwann wurde mir klar, dass ich zu viele solcher Konvertierungen hatte, um Zeigeroperatoren zu funktionieren, und dass ich theoretisch in der Lage sein würde, einen einzigen variablen Konvertierungsoperator zu schreiben. Hier ist eine Klasse, eine solche variadische Betreiber Umsetzung:Variadic Funktionszeiger Umwandlung

struct foobar 
{ 
    template<typename... Args> 
    using fptr_t = void(*)(Args... args); 

    template<typename... Args> 
    operator fptr_t<Args...>() const 
    { 
     return [](Args... args) { 
      // Whatever 
     }; 
    } 
}; 

Wie Sie sehen können, habe ich die Lambda-Konvertierung verwendet Zeiger auf Funktion des Umwandlungsoperator zu implementieren, was aber kein Problem ist, da jede Funktion Objekt Ich habe staatenlos ist. Das Ziel war es, die Klasse wie folgt zu verwenden:

int main() 
{ 
    void(*foo)(int) = foobar(); 
    void(*bar)(float, double) = foobar(); 
} 

g ++ kein Problem hat, diesen Code mit der erwarteten Semantik kompilieren. Allerdings Klirren ++ rejects it mit einer Vorlage Substitution Fehlerfehler:

main.cpp:21:11: error: no viable conversion from 'foobar' to 'void (*)(int)' 
    void(*foo)(int) = foobar(); 
     ^   ~~~~~~~~ 
main.cpp:11:5: note: candidate function [with Args = int] 
    operator fptr_t<Args...>() const 
    ^
1 error generated. 

Beachten Sie, dass Klappern ++ hat kein Problem mit einer solchen Umwandlung Betreiber solange keine variadische Vorlagen beteiligt sind. Wenn ich einen einzelnen Template-Parameter verwende, hat er kein Problem, den Code zu kompilieren. Soll nun der obige Code vom Compiler akzeptiert oder abgelehnt werden?

+4

ich dies die [wie diese gleichen Fehler] denken (https: // llvm.org/bugs/show_bug.cgi?id=24032). Es gibt auch eine verknüpfte SO-Frage. Richard Smith [sagt einen Fehler] (http://stackoverflow.com/questions/31225888/pre-typedefing-a-variadic-function-pointer-argument#comment50471304_31225888), also glaube ich ihm :). –

+0

Workaround: konvertieren mit 'Vorlage Operator F *()', fügen Sie Sfinae Test, dass es ein Funktionstyp ist, extrahieren Args mit Traits, entpacken mit Hilfe, verwenden Sie Helfer, um Zeiger zu konvertieren? – Yakk

Antwort

1

Ein Lambda kann nur in einen Funktionszeiger konvertiert werden, wenn er nicht erfasst wird, daher sollte der Code funktionieren. Dies wird in den Standard 5.1.2/p6 Lambda-Ausdrücke [expr.prim.lambda] (Hervorhebung von mir) gerechtfertigt:

The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function with C++ language linkage (7.5) having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

So würde ich es als CLANG Bug-Datei.

Als Arbeit um für CLANG, können Sie es zu einem std::function umwandeln kann, wie unten dargestellt:

struct foobar 
{ 
    template<typename... Args> 
    using fptr_t = void(*)(Args... args); 

    template<typename... Args> 
    operator std::function<void(Args...)>() const 
    { 
     return [](Args... args) { 
      //... 
     }; 
    } 
}; 

int main() 
{ 
    std::function<void(int)> f1 = foobar(); 
    std::function<void(double, float)> f2 = foobar(); 
    f1(1); 
    f2(2.0, 1.0f); 
} 

Live Demo

+0

Nun ja, ich weiß das alles. Ich meine, ich frage nicht nach einer Lösung für mein Problem (ich habe schon eine Weile daran gearbeitet). Ich frage nur nach einer Sprachanwalts-Antwort, um zu wissen, an welchen Compiler ich einen Fehlerbericht senden soll: p – Morwenn

+0

@Morwenn Sie werden einen Fehlerbericht an CLANG: P. – 101010