c++lambdaoverloadingc++17function-object

Overload a lambda function


How to overload a simple local lambda function?

SSE of original problem:

#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;
}

The error messages

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

Please don't mind not checking user input, this is an SSE.


Solution

  • No, you can not overload the lambda!

    The lambdas are anonymous functors(i.e. unnamed function objects), and not simple functions. Therefore, overloading those objects not possible. What you basically trying to do is almost

    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
    

    Which is not possible, as the same variable name can not be reused in C++.


    However, in we have if constexpr by which one can instantiate the only branch which is true at compile time.

    Meaning the possible solutions are:

    Using variabe template you can do something like. (See a live demo online)

    #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];
        }
    };
    

    and call it like

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

    Using generic lambda(since ), the above will be: (See a live demo online)

    #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];
        }
    };
    

    and call the lambda as you do now:

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