Wie kann man eine einfache lokale Lambda-Funktion überladen?
SSE des ursprünglichen Problems:
#include <iostream>
#include <map>
void read()
{
static std::string line;
std::getline(std::cin, line);
auto translate = [](int idx)
{
constexpr static int table[8]{ 7,6,5,4,3,2,1,0 };
return table[idx];
};
auto translate = [](char c)
{
std::map<char, int> table{ {'a', 0}, {'b', 1}, {'c', 2}, {'d', 3},
{'e', 4}, {'f', 5}, {'g', 6}, {'h', 7} };
return table[c];
};
int r = translate(static_cast<int>(line[0]));
int c = translate(static_cast<char>(line[1]));
std::cout << r << c << std::endl;
}
int main()
{
read();
return 0;
}
Die Fehlermeldungen
error: conflicting declaration 'auto translate'
note: previous declaration as 'read()::<lambda(int)> translate'
Bitte haben Sie nichts dagegen, Benutzereingaben nicht zu überprüfen, dies ist eine SSE.
c++
lambda
overloading
c++17
function-object
snoopy
quelle
quelle
translate
sind nur lokale Variablen, die denselben Namen nicht wiederverwenden können.Antworten:
Nein, Sie können das Lambda nicht überladen!
Die Lambdas sind anonyme Funktoren (dh unbenannte Funktionsobjekte) und keine einfachen Funktionen. Daher ist eine Überladung dieser Objekte nicht möglich. Was Sie im Grunde versuchen, ist fast
Dies ist nicht möglich, da derselbe Variablenname in C ++ nicht wiederverwendet werden kann.
In c ++ 17 haben wir jedoch
if constexpr
die Möglichkeit, den einzigen Zweig zu instanziieren, der zur Kompilierungszeit wahr ist.Die möglichen Lösungen sind:
decltype
für dieif constexpr
Prüfung verwendet wird. (Credits @NathanOliver )Mit variabe template können Sie so etwas tun. ( Sehen Sie eine Live-Demo online )
und nenne es wie
Bei Verwendung von generischem Lambda (seit c ++ 14 ) gilt Folgendes: ( Sehen Sie sich eine Live-Demo online an. )
und nenne das Lambda wie jetzt:
quelle
else if
seinelse if constexpr
. Zweitens, warum eine variable Vorlage verwenden? Sie könnten einfach das Lambda generisch machen und Ihre Checls würdenif constexpr (std::is_same_v<decltype(idx), int>)
undelse if constexpr (std::is_same_v<decltype(idx), char>)
Lambdas sind im Grunde syntaktischer Zucker für lokal definierte Funktoren. Soweit ich weiß, sollten sie niemals überladen werden, um mit verschiedenen Parametern aufgerufen zu werden. Beachten Sie, dass jeder Lambda-Ausdruck von einem anderen Typ ist, sodass Ihr Code trotz des unmittelbaren Fehlers nicht wie beabsichtigt funktionieren kann.
Sie können jedoch einen Funktor mit einer Überlastung definieren
operator()
. Dies ist genau das, was Sie von Lambdas bekommen würden, wenn es möglich wäre. Sie erhalten nur nicht die knappe Syntax.Etwas wie:
quelle
Daher gelten die Regeln zum Überladen von Namen nur für bestimmte Arten der Suche nach Funktionsnamen (sowohl freie als auch Methoden).
Lambdas sind keine Funktionen, sondern Objekte mit einem Funktionsaufrufoperator. Eine Überladung zwischen zwei verschiedenen Lambdas kann also nicht auftreten.
Jetzt können Sie die Überlastungsauflösung für die Arbeit mit Funktionsobjekten erhalten, jedoch nur im Rahmen eines einzelnen Objekts. Und wenn es mehr als eine gibt
operator()
, kann eine Überlastungsauflösung zwischen ihnen wählen.Ein Lambda hat jedoch keine offensichtliche Möglichkeit, mehr als ein Lambda zu haben
operator()
. Wir können eine einfache (in c ++ 17 ) Dienstprogrammklasse schreiben , um uns zu helfen:und eine Abzugsanleitung:
Mit diesen beiden können wir zwei Lambdas überladen:
und fertig.
Das Schreiben
overloaded
ist sowohl in C ++ 14 als auch in C ++ 11 möglich , erfordert jedoch mehr Arbeit und ist weniger elegant. Sobald Sie sich des Problems bewusst sind, sollte es nicht schwierig sein, eine Lösung zu finden, die den Anforderungen Ihres Compilers in Bezug auf C ++ - Funktionen entspricht.quelle
variadic generic lamda
+if constexpr
, um Anrufe zu trennen?