Consider this:
template<typename T>
struct base_t
{
auto& f(int x) { return (T&)*this; }
auto& f(char x) { return (T&)*this; }
};
struct derived_t : base_t<derived_t>
{
};
void test()
{
derived_t instance;
auto lambda = [&](derived_t&(derived_t::*g)(char))
{
(instance.*g)('a');
//instance.f('a');
};
lambda(&derived_t::f);
}
Without commenting in that particular line ( //instance.f('a');
) , I get the following error (MSVC 2019):
error C2664: 'void test::<lambda_1>::operator ()(derived_t &(__cdecl derived_t::* )(char)) const': cannot convert argument 1 from 'overloaded-function' to 'derived_t &(__cdecl derived_t::* )(char)'
When the line isn't commented out, it compiles just fine.
Why does referencing f
inside lambda
magically allow the compiler to convert this overloaded function?
Furthermore, without CRTP, this doesn't happen at all.
Edit: Additionally, as pointed out by @Jarod42,
Being explicit on return type auto& -> T& solves the issue.
If you use a named function instead of a lambda, the problem disappears. So apparently the interaction of lambdas and templates is relevant.
auto&
->T&
Demo solves issue for gcc and msvc. – Kathiekathleenreturn *static_cast<T*>(this);
affect the outcome? – Sylphf
instantiate it, if you use the other overload, gcc/msvc still fail Demo. That would explain gcc/msvc behavior. – Kathiekathleenauto
interact with that (we might seeauto
as template function)... – Kathiekathleen