c++ - Sobrecargar una función lambda




overloading c++17 (2)

¿Cómo sobrecargar una función lambda local simple?

SSE del 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;
}

Los mensajes de error

error: conflicting declaration 'auto translate'
note: previous declaration as 'read()::<lambda(int)> translate'

Por favor, no le importe no verificar la entrada del usuario, este es un SSE.


¡No, no puedes sobrecargar la lambda!

Las lambdas son functores anónimos (es decir, objetos de función sin nombre) y no funciones simples. Por lo tanto, sobrecargar esos objetos no es posible. Lo que básicamente intentas hacer es casi

struct <some_name>
{
    int operator()(int idx) const
    {
        return {}; // some int
    }
}translate; // >>> variable name

struct <some_name>
{
    int operator()(char idx) const
    {
        return {}; // some int
    }
}translate; // >>> variable name

Lo cual no es posible, ya que el mismo nombre de variable no se puede reutilizar en C ++.

Sin embargo, en c ++ 17 tenemos if constexpr por el cual se puede instanciar la única rama que es verdadera en tiempo de compilación.

Lo que significa que las posibles soluciones son:

  • Una sola plantilla variabe lambda. o
  • Un lambda genérico y encuentre el tipo de parámetro usando decltype para la verificación if constexpr . (Créditos @NathanOliver )

Usando la plantilla variabe puedes hacer algo como. ( Vea una demostración en vivo en línea )

#include <type_traits> // std::is_same_v

template<typename T>
constexpr auto translate = [](T idx) 
{
    if constexpr (std::is_same_v<T, int>)
    {
        constexpr static int table[8]{ 7,6,5,4,3,2,1,0 };
        return table[idx];
    }
    else if constexpr (std::is_same_v<T, char>)
    {
        std::map<char, int> table{ {'a', 0}, {'b', 1}, {'c', 2}, {'d', 3}, {'e', 4}, {'f', 5}, {'g', 6}, {'h', 7} };
        return table[idx];
    }
};

y llámalo como

int r = translate<int>(line[0]);
int c = translate<char>(line[1]);

Usando lambda genérico (desde c ++ 14 ), lo anterior será: ( Vea una demostración en vivo en línea )

#include <type_traits> // std::is_same_v

constexpr auto translate = [](auto idx) 
{
    if constexpr (std::is_same_v<decltype(idx), int>)
    {
        constexpr static int table[8]{ 7,6,5,4,3,2,1,0 };
        return table[idx];
    }
    else if constexpr (std::is_same_v<decltype(idx), char>)
    {
        std::map<char, int> table{ {'a', 0}, {'b', 1}, {'c', 2}, {'d', 3}, {'e', 4}, {'f', 5}, {'g', 6}, {'h', 7} };
        return table[idx];
    }
};

y llama a la lambda como lo haces ahora:

int r = translate(static_cast<int>(line[0]));
int c = translate(static_cast<char>(line[1]));

Las lambdas son básicamente azúcar sintáctico para functores definidos localmente. Hasta donde yo sé, nunca fueron destinados a ser sobrecargados para ser llamados con diferentes parámetros. Tenga en cuenta que cada expresión lambda es de un tipo diferente, por lo que incluso el error inmediato a un lado, su código no puede funcionar según lo previsto.

Sin embargo, puede definir un functor con un operator() sobrecargado operator() . Esto sería exactamente lo que obtendría de lambdas si fuera posible. Simplemente no obtienes la sintaxis concisa.

Algo como:

void read()
{
    static std::string line;

    struct translator {
          int operator()(int idx) { /* ... */ }
          int operator()(char x)  { /* ... */ }
    };
    translator translate;


    std::getline(std::cin, line);

    int r = translate(static_cast<int>(line[0]));
    int c = translate(static_cast<char>(line[1]));

    std::cout << r << c << std::endl;
}




function-object