Frage Automatischer Zerfall von Lambda zum Funktionszeiger beim Übergehen zur Template-Funktion


Gibt es eine Möglichkeit, einen Lambda-Zerfall zu einem Zeiger zu machen, ohne explizit auf die richtige Signatur zu verweisen? Dies würde etwas Code aufräumen:

template<typename T> T call(T(*func)()){ return func(); }
int ptr(){ return 0; }
int main(){
    auto ret1 = call(ptr);
    auto ret2 = call((int(*)())([]{ return 0; }));
    auto ret3 = call([]{ return 0; });  //won't compile
}

Es ist offensichtlich, dass ein Anruf an call funktioniert nur, wenn das Lambda zu einem Zeiger abfällt, aber ich vermute, dass dies nur passieren kann, nachdem die richtige Funktionsüberladung / Vorlage gewählt wurde. Leider kann ich nur an Lösungen denken, die Vorlagen beinhalten, um ein Lambda zu erstellen mit irgendeiner Unterschrift Verfall, also bin ich wieder auf Platz eins.


6
2018-03-10 11:27


Ursprung


Antworten:


Sie können Ihr Lambda ändern, um das Unäre zu verwenden + Operator: +[]{ return 0; }

Dies funktioniert, weil unary plus auf Zeiger angewendet werden kann und die implizite Umwandlung in den Funktionszeiger auslöst.


12
2018-03-10 11:37



Warum würden Sie sich unnötigerweise darauf beschränken, Zeiger ohne ausgefallene Argumente und Lambdas ohne Captures zu verwenden, was die große Familie von Funktoren (z. std::function, irgendwelche Ergebnisse von std::bind und alles andere, was ein passendes hat operator())

Erweitern Sie einfach Ihre Funktionssignatur:

template <typename F> 
auto call(F func) -> decltype(func()) { 
  return func(); 
}

int ptr() { return 0; }

int g(int i = 0) {return i;}

int main() {
    auto ret1 = call(ptr);
    auto ret2 = call((int(*)())([]{ return 0; })); //tedious, but works
    auto ret3 = call([]{ return 0; });  //ok now.

    auto ret4 = call(g); //ok now!
    int i = 42;
    auto ret5 = call([=]{return i;}); //works, too!
    auto ret6 = call(std::bind(g, i)); //and so on...
}

1
2018-03-10 11:44