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.
You overload a function name f by declaring more than one function with the name f in the same scope. The declarations of f must differ from each other by the types and/or the number of arguments in the argument list.
Function overloading is a feature of object-oriented programming where two or more functions can have the same name but different parameters. When a function name is overloaded with different jobs it is called Function Overloading.
C++ lets you specify more than one function of the same name in the same scope. These functions are called overloaded functions, or overloads. Overloaded functions enable you to supply different semantics for a function, depending on the types and number of its arguments.
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 c++17 we have if constexpr
by which one can instantiate the only branch which is true at compile time.
Meaning the possible solutions are:
decltype
for the if constexpr
check.(credits @NathanOliver)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 c++14), 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]));
So the rules for overloading names only apply to certain kinds of lookup of function names (both free and methods).
Lambdas are not functions, they are objects with a function-call operator. So overloading cannot occur between two different lambdas.
Now, you can get overload resolution to work with function objects, but only within the scope of a single object. And then if there is more than one operator()
, overload resoltion can pick between them.
A lambda, however, has no obvious way to have more than one operator()
. We can write a simple (in c++17) utility class to help us:
template<class...Fs>
struct overloaded : Fs... {
using Fs::operator()...;
};
and a deduction guide:
template<class...Fs>
overloaded(Fs...) -> overloaded<Fs...>;
with these two, we can overload two lambdas:
static std::string line;
std::getline(std::cin, line);
auto translate_int = [](int idx){
constexpr static int table[8] {7,6,5,4,3,2,1,0};
return table[idx];
};
auto translate_char = [](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];
};
auto translate = overloaded{ translate_int, translate_char };
int r = translate(static_cast<int>(line[0]));
int c = translate(static_cast<char>(line[1]));
and done.
Writing overloaded
is possible in both c++14 and c++11 but requires more work and is less elegant. Once you are aware of the problem, finding a solution that matches what your particular compiler supports in the way of C++ features shouldn't be hard.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With