Como sobrecarregar uma função lambda local simples?
SSE do problema original:
#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;
}
As mensagens de erro
error: conflicting declaration 'auto translate'
note: previous declaration as 'read()::<lambda(int)> translate'
Por favor, não se importe de não verificar a entrada do usuário, este é um SSE.
c++
lambda
overloading
c++17
function-object
snoopy
fonte
fonte
translate
são apenas variáveis locais que não podem reutilizar o mesmo nome.Respostas:
Não, você não pode sobrecarregar o lambda!
Os lambdas são functores anônimos (ou seja, objetos de função sem nome), e não funções simples. Portanto, sobrecarregar esses objetos não é possível. O que você basicamente está tentando fazer é quase
O que não é possível, pois o mesmo nome de variável não pode ser reutilizado no C ++.
No entanto, em c ++ 17 , temos
if constexpr
como instanciar o único ramo que é verdadeiro no tempo de compilação.Significando que as soluções possíveis são:
decltype
para aif constexpr
verificação. ( Credits @NathanOliver )Usando o modelo variabe, você pode fazer algo parecido. ( Veja uma demonstração ao vivo online )
e chame assim
Usando lambda genérico (desde c ++ 14 ), o acima será: ( Veja uma demonstração ao vivo on-line )
e chame o lambda como você faz agora:
fonte
else if
precisa serelse if constexpr
. Em segundo lugar, por que usar um modelo de variável? Você poderia apenas fazer a lambda genéricos e seus checls se tornariaif constexpr (std::is_same_v<decltype(idx), int>)
eelse if constexpr (std::is_same_v<decltype(idx), char>)
Lambdas são basicamente açúcar sintático para functores definidos localmente. Tanto quanto eu sei, eles nunca foram feitos para serem sobrecarregados para serem chamados com parâmetros diferentes. Observe que toda expressão lambda é de um tipo diferente; portanto, mesmo com o erro imediato, seu código não pode funcionar como pretendido.
No entanto, você pode definir um functor com uma sobrecarga
operator()
. Isso será exatamente o que você obteria das lambdas, se possível. Você simplesmente não obtém a sintaxe concisa.Algo como:
fonte
Portanto, as regras para sobrecarregar nomes se aplicam apenas a certos tipos de pesquisa de nomes de funções (livres e métodos).
Lambdas não são funções, são objetos com um operador de chamada de função. Portanto, a sobrecarga não pode ocorrer entre duas lambdas diferentes.
Agora, você pode obter uma resolução de sobrecarga para trabalhar com objetos de função, mas apenas no escopo de um único objeto. E então, se houver mais de um
operator()
, a resolução de sobrecarga poderá escolher entre eles.Um lambda, no entanto, não tem uma maneira óbvia de ter mais de um
operator()
. Podemos escrever uma classe de utilitário simples (em c ++ 17 ) para nos ajudar:e um guia de dedução:
com esses dois, podemos sobrecarregar duas lambdas:
E feito.
A escrita
overloaded
é possível no c ++ 14 e no c ++ 11, mas requer mais trabalho e é menos elegante. Quando você estiver ciente do problema, não será difícil encontrar uma solução que corresponda ao que seu compilador específico oferece como recursos de C ++.fonte
variadic generic lamda
+if constexpr
para separar as chamadas?