Could anyone explain why compilers (g++, visual c++) fail to deduce the template argument in this case?
struct MyClass
{
void Foo(int x)& {}
void Foo(int x)&& {}
};
template<typename T>
void CallFoo(void(T::*func)(int)&)
{
//create instance and call func
}
int main()
{
CallFoo(&MyClass::Foo); // Fails to deduce T
}
Why compilers cannot deduce T to MyClass? This happens only for methods overloaded by ref qualifiers. If a method is overloaded by const-ness or parameter types, everything works fine. It seems that only Clang can deduce T in this case.
Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17's Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector.
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
You cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };
Summarizing discussion in the comments: the support for reference-qualified member functions as template arguments is a relatively new feature for some compilers. However, the latest versions of most compilers will compile such code.
For example:
#include <iostream>
struct MyClass
{
void Foo(int) const &
{
std::cout << "calling: void Foo(int) const &\n";
}
void Foo(int) const &&
{
std::cout << "calling: void Foo(int) const &&\n";
}
};
template<typename T>
void CallFoo_lvalue(void (T::*foo)(int) const &)
{
T temp;
(temp.*foo)(0);
}
template<typename T>
void CallFoo_rvalue(void (T::*foo)(int) const &&)
{
(T{}.*foo)(0);
}
int main()
{
CallFoo_lvalue(&MyClass::Foo);
CallFoo_rvalue(&MyClass::Foo);
}
Will compile with:
producing the following output:
calling: void Foo(int) const &
calling: void Foo(int) const &&
For those who are wondering what &
and &&
are for: here's the quote from @JustinTime:
Basically, & is the lvalue ref-qualifier, and && is the rvalue ref-qualifier (binds to temporary object); in his example, MyClass m; m.Foo(3); would call the top one, while MyClass{}.Foo(3); would call the bottom one. They act on the implicit object parameter; lvalue ref-qualifier binds to lvalue reference, and rvalue ref-qualifier binds to rvalue reference (functions that have neither take the parameter as lvalue reference, but let it bind to either). Note that they don't actually change *this's type.
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