Jak przeciążyć prostą lokalną funkcję lambda?
SSE oryginalnego problemu:
#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;
}
Komunikaty o błędach
error: conflicting declaration 'auto translate'
note: previous declaration as 'read()::<lambda(int)> translate'
Nie przejmuj się sprawdzaniem danych wejściowych użytkownika, to jest SSE.
c++
lambda
overloading
c++17
function-object
wścibski
źródło
źródło
translate
są tylko lokalnymi zmiennymi, które nie mogą ponownie użyć tej samej nazwy.Odpowiedzi:
Nie, nie możesz przeciążać lambda!
Lambdas to anonimowe funktory (tj. Nienazwane obiekty funkcyjne), a nie proste funkcje. Dlatego przeciążenie tych obiektów nie jest możliwe. W zasadzie próbujesz to zrobić
Nie jest to możliwe, ponieważ tej samej nazwy zmiennej nie można ponownie użyć w C ++.
Jednak w c ++ 17 mamy
if constexpr
instancję jedynej gałęzi, która jest prawdziwa w czasie kompilacji.Znaczenie możliwych rozwiązań to:
decltype
doif constexpr
kontroli. (Kredyty @NathanOliver )Za pomocą szablonu variabe możesz zrobić coś takiego. ( Zobacz prezentację online na żywo )
i nazwać to tak
Używając ogólnej lambda (od c ++ 14 ), powyższe będzie: ( Zobacz demo na żywo online )
i zawołaj lambda tak jak teraz:
źródło
else if
musisz byćelse if constexpr
. Po drugie, po co stosować zmienny szablon? Możesz po prostu uczynić lambda ogólną, a twoi checlowie staną sięif constexpr (std::is_same_v<decltype(idx), int>)
ielse if constexpr (std::is_same_v<decltype(idx), char>)
Jagnięta są zasadniczo składniowym cukrem dla lokalnie zdefiniowanych funktorów. O ile mi wiadomo, nigdy nie miały być przeciążone, aby wywoływać je różnymi parametrami. Zauważ, że każde wyrażenie lambda jest innego typu, więc nawet pomijając natychmiastowy błąd, twój kod nie może działać zgodnie z przeznaczeniem.
Można jednak zdefiniować funktor z przeciążeniem
operator()
. Będzie to dokładnie to, co dostaniesz od lambdas, jeśli to możliwe. Po prostu nie otrzymujesz zwięzłej składni.Coś jak:
źródło
Zatem zasady przeciążania nazw dotyczą tylko niektórych rodzajów wyszukiwania nazw funkcji (zarówno wolnych, jak i metod).
Lambdy nie są funkcjami, są obiektami z operatorem wywołania funkcji. Zatem przeciążenie nie może wystąpić między dwoma różnymi lambdami.
Teraz możesz uzyskać rozdzielczość przeciążenia do pracy z obiektami funkcyjnymi, ale tylko w zakresie pojedynczego obiektu. A jeśli jest ich więcej
operator()
, rozwiązanie przeciążenia może wybierać między nimi.Jednak lambda nie ma oczywistego sposobu na posiadanie więcej niż jednego
operator()
. Możemy napisać prostą (w c ++ 17 ) klasę użyteczności, która pomoże nam:oraz przewodnik dedukcyjny:
dzięki tym dwóm możemy przeciążyć dwa lambda:
i zrobione.
Pisanie
overloaded
jest możliwe zarówno w c ++ 14, jak i c ++ 11, ale wymaga więcej pracy i jest mniej eleganckie. Gdy zdasz sobie sprawę z problemu, znalezienie rozwiązania, które pasuje do tego, co obsługuje Twój kompilator, w zakresie funkcji C ++, nie powinno być trudne.źródło
variadic generic lamda
+if constexpr
umożliwia oddzielne połączenia?