template<typename T, typename F, typename ...Args>
auto f(F h, Args&&... args) -> decltype(h(args...)) {
T* t = new T(); // Don't worry, my actual code doesn't do this
return (t->h)(args...);
}
struct G {
int g() {
return 5;
}
};
int main() {
int k = f<G>(&G::g);
}
Microsoft's compiler says error C2672: 'f': no matching overloaded function found
and error C2893: Failed to specialize function template 'unknown-type f(F,Args &&...)'
.
Clang's compiler says note: candidate template ignored: substitution failure [with T = G, F = int (G::*)(), Args = <>]: called object type 'int (G::*)()' is not a function or function pointer
and error: no matching function for call to 'f'
.
I'm pretty sure int (G::*)()
is a function pointer ... ? What am I missing? (All of this worked fine before I added the return type.)
I'm pretty sure
int (G::*)()
is a function pointer ... ? What am I missing?
Non exactly: int (G::*)()
is a pointer to a non-static method. That isn't exactly the same things and require a little different syntax to call it.
So, instead of
return (t->h)(args...);
you should add a *
and call h()
as follows
return (t->*h)(args...);
// ........^ add this *
The decltype()
is also wrong. If you can use at least C++14, you can avoid it and simply use auto
as return type
template <typename T, typename F, typename ...Args>
auto f (F h, Args&&... args) {
T* t = new T();
return (t->*h)(args...);
}
otherwise, if you must use C++11, you can include <utility>
and use std::declval()
as follows
template <typename T, typename F, typename ...Args>
auto f(F h, Args&&... args) -> decltype((std::declval<T*>()->*h)(args...)) {
T* t = new T(); // .................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return (t->*h)(args...);
}
But there is another way to write your f()
function: deducing the returned type (so avoiding the auto
, the decltype()
and the std::declval()
) and the arguments of h()
You can write f()
as follows
template<typename R, typename T, typename ... As1, typename ... As2>
R f(R(T::*h)(As1...), As2 && ... args) {
T* t = new T();
return (t->*h)(args...);
}
and you avoid to explicit the G
type calling it
int k = f(&G::g);
// .....^^^^^^^^ no more explicit <G> needed
because the T
template type is deduced from the argument &G::g
.