Reputation: 812
Below I have a template function named ProxyCall, which accepts an object, a member function and its arguments. It simply forwards the call to the member function.
I would like to be able to call the function without using template qualifiers (imagine tons of such calls with multiple arguments). The type deduction mostly works but the compilers (both msvc and gcc 4.9) barf when I try to pass const reference parameters as in the example.
#include <string>
struct Widget {
void f(const std::string& s, bool b) {}
};
template<typename T, typename... Args>
void ProxyCall(T &obj, void(T::*method)(Args...), Args&&... args) {
(obj.*method)(std::forward<Args>(args)...);
}
int main(int argc, char* argv[])
{
Widget w;
std::string s;
ProxyCall<Widget, const std::string&, bool>(w, &Widget::f, s, true); // OK
ProxyCall(w, &Widget::f, (const std::string&)s, true); // also OK
ProxyCall(w, &Widget::f, s, true); // ERROR: template parameter is ambiguous
return 0;
}
My question is: How can I modify the above code so that the compiler would automatically deduce the types without resorting to explicit template qualifiers or explicit casting. It seems this should be possible considering that the compiler already knows that exact arguments types from the signature of Widget::f.
Upvotes: 5
Views: 731
Reputation: 60989
template<typename T, typename... Args>
void ProxyCall(T &obj, void(T::*method)(Args...), Args&&... args) {
(obj.*method)(std::forward<Args>(args)...);
}
Args
is deduced from both the second argument and the trailing arguments to ProxyCall
.
In your third case, since s
is not const
, Args
is deduced to [std::string&, bool]
(recall the rules for reference collapsing and forwarding references). However, the member functions signature is clearly different. Thus two different types are deduced for the first type in Args
, which leads to a deduction failure.
Instead, make both the parameter types and the arguments independent - and forward the object argument, for the sake of ref-qualifiers:
template<typename T, typename F, typename... Args>
void ProxyCall(T&& obj, F method, Args&&... args) {
(std::forward<T>(obj).*method)(std::forward<Args>(args)...);
}
Upvotes: 3