I want to have a struct that takes an arbitrary number of lambdas and serve as a central calling point for all their call operators.
If the call operator is invoked with an argument list that doesn't match any of the lambdas given on construction, a default call operator should be called.
I thought the following code would accomplish exactly this. The call operator for every lambda is "lifted" into the Poc
class via using
.
template <typename ...Lambdas>
struct Poc : Lambdas...
{
using Lambdas::operator() ...; // Lift the lambda operators into the class
template <typename ...Ts>
auto operator() (Ts...)
{
std::cout << "general call" << std::endl;
}
};
// Deduction guide
template <typename ...Ts>
Poc(Ts... ts)->Poc<Ts...>;
int main()
{
auto l_int = [](int) {std::cout << "int" << std::endl; };
Poc poc{l_int};
poc(1);//calls the default operator. why?
return 0;
}
When I don't have the default call operator in the struct, everything works as expected (with valid argument lists). If I add it to the struct (as in the code above), the default operator gets called everytime, no matter which arguments I call it with.
In my understanding, the lambda-call-operators and the structs (default) call-operator are present in the same scope. Therefore, they should all be looked at for the overload resolution. Since the lamdba-operator is more specific than the generic default operator, it should be chosen.
Apparently that is not the case. Why is that?
I tested on Microsoft Visual C++, Clang and GCC (all in their latest versions).
Edit:
Inheritance: Overriding of functions occurs when one class is inherited from another class. Overloading can occur without inheritance. Function Signature: Overloaded functions must differ in function signature ie either number of parameters or type of parameters should differ.
The process of selecting the most appropriate overloaded function or operator is called overload resolution. Suppose that f is an overloaded function name. When you call the overloaded function f() , the compiler creates a set of candidate functions.
Overloading allows several function definitions for the same name, distinguished primarily through different argument types; it is typically resolved at compile-time. Inheritance allows subclasses to define more special versions of the same function; it is typically resolved at run-time.
The reason is the same as explained in the case of the C++ program. In C#, just like in C++, there is no overload resolution between class Base and class Derived. Also, there is no overloading across scopes and derived class scopes are not an exception to this general rule.
It's simple when you spot it: your operator is not const
-qualified, while the lambda's one is (unless you define the lambda as mutable
). Hence, it is a better match for your non-const instance of Poc
.
Just add the missingconst
:
auto operator() (Ts...) const
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