Disambiguate overloaded member function pointer being passed as template parameter
The issue is here:
l.call(&foo::func, "hello");
l.call(&foo::func, 0.5);
For both lines, the compiler doesn't know which foo::func
you are referring to. Hence, you have to disambiguate yourself by providing the type information that is missing (i.e., the type of foo:func
) through casts:
l.call(static_cast<void (foo::*)(const std::string&)>(&foo::func), "hello");
l.call(static_cast<void (foo::*)(const double )>(&foo::func), 0.5);
Alternatively, you can provide the template arguments that the compiler cannot deduce and that define the type of func
:
l.call<void, const std::string&>(&foo::func, "hello");
l.call<void, double >(&foo::func, 0.5);
Notice that you have to use double
and not const double
above. The reason is that generally double
and const double
are two different types. However, there's one situation where double
and const double
are considered as if they were the same type: as function arguments. For instance,
void bar(const double);
void bar(double);
are not two different overloads but are actually the same function.
Get pointer to overloaded function that would be called
There is no way to get the function of an overload-set which would be called with the given arguments, unless you already know its signature.
And if you know, what's the point?
The problem is that for any given arguments, taking into account implicit conversions, references, cv-qualifiers, noexcept
, old-style vararg, default arguments, and maybe also literal 0 being a null pointer constant, there are an infinite number of function-signatures which would match. And there is currently no facility for "just" listing all candidates.
decltype for overloaded member function
More "closely", as far as I understand, means you want to specify the function arguments of print
. That is, for example, you select int, int
, then get back the result-type of Foo{}.print(int{},int{})
, and thereafter construct a function pointer from all the available information.
Here is an alias template which does that for you in a general way:
template<typename ... Args>
using ptr_to_print_type = decltype(std::declval<Foo>().print(std::declval<Args>() ...)) (Foo::*)(Args ...);
You could also use std::result_of
instead of the std::declval
stuff, but I like the latter more.
You can use the above as
func<ptr_to_print_type<int,int> >();
EDIT: as asked for by @JavaLover, which btw seems like an unsuitable name for such horrible C++ shit :-), here is the same as above using std::result_of
(untested now tested and wrong):
//------ does not compile for overloaded functions --------
template<typename ... Args>
using ptr_to_print_type = std::result_of_t<decltype(&Foo::print)(Foo, Args ...)> (Foo::*)(Args ...)
//------ does not compile for overloaded functions --------
You could further abstract away the Foo
but not the print
(unless you're using macros).
unresolved overloaded function type with member function pointer and templates
I have found the mistake. You can't send a member function pointer to a template parameter that is stored in a variable, even a constexpr
one.
constexpr auto theMethod = &TestClass::setFoo;
// won't work
call(&Caller::callme<decltype(theMethod), theMethod>);
In a template parameter that is a member function pointer, it is required that it is wrote directly:
constexpr auto theMethod = &TestClass::setFoo;
// won't work
call(&Caller::callme<decltype(theMethod), &TestClass::setFoo>);
My solution was to pass around an std::integral_constant
instead of the function pointer directly.
using methodType = std::integral_constant<decltype(&TestClass::setFoo), &TestClass::setFoo>;
call(&Caller::callme<methodType>);
The non-type template parameter of pointer to overloaded member functions with inheritance
I found a workaround fitting my requirements. Hoping it be helpful for anyone in need. I got stuck for days...
The idea is using a function template to match a particular overload, and then pass the correct type to G
. A layer of indirection always saves the world.
template <typename T>
auto forward_pmf_with_signature( int(T::*pmf)() ) -> decltype(pmf);
G<decltype(forward_pmf_with_signature(&B::f)), &B::f> {}; // works
G
is used without the awareness of A
and selects the correct overload, cool.
Now the new problem is that I found G<decltype(forward_pmf_with_signature(&B::f)), &B::f>
is redundant and error-prone. It's trivial to use a macro USE_G(&B::f)
to simply the code, but it seems to me that it's not easy, or even possible to do the simplification in a semantic way.
generic member function pointer as a template parameter
You could try something like this:
template <typename T, typename R, typename ...Args>
R proxycall(T & obj, R (T::*mf)(Args...), Args &&... args)
{
return (obj.*mf)(std::forward<Args>(args)...);
}
Usage: proxycall(obj, &hello::f);
Alternatively, to make the PTMF into a template argument, try specialization:
template <typename T, T> struct proxy;
template <typename T, typename R, typename ...Args, R (T::*mf)(Args...)>
struct proxy<R (T::*)(Args...), mf>
{
static R call(T & obj, Args &&... args)
{
return (obj.*mf)(std::forward<Args>(args)...);
}
};
Usage:
hello obj;
proxy<void(hello::*)(), &hello::f>::call(obj);
// or
typedef proxy<void(hello::*)(), &hello::f> hello_proxy;
hello_proxy::call(obj);
How do I specify a pointer to an overloaded function?
You can use static_cast<>()
to specify which f
to use according to the function signature implied by the function pointer type:
// Uses the void f(char c); overload
std::for_each(s.begin(), s.end(), static_cast<void (*)(char)>(&f));
// Uses the void f(int i); overload
std::for_each(s.begin(), s.end(), static_cast<void (*)(int)>(&f));
Or, you can also do this:
// The compiler will figure out which f to use according to
// the function pointer declaration.
void (*fpc)(char) = &f;
std::for_each(s.begin(), s.end(), fpc); // Uses the void f(char c); overload
void (*fpi)(int) = &f;
std::for_each(s.begin(), s.end(), fpi); // Uses the void f(int i); overload
If f
is a member function, then you need to use mem_fun
, or for your case, use the solution presented in this Dr. Dobb's article.
How can I have a function pointer template as a template parameter?
C++ doesn't allow non-type template template parameters. That means you can't have a parameter-pack for your member-function pointer parameter.
Assuming you're using C++17 or newer, you can use an auto
template parameter instead:
template<typename T, auto func>
public:
template<typename... Args>
void update(Args... args)
{
for (T* handler : handlers_)
{
(handler->*func)(std::forward<Args>(args)...);
}
}
private:
std::vector<T*> handlers_;
};
Live Demo
Technically that will accept any object for func
, but assuming update
is called, then (handler->*func)(std::forward<Args>(args)...)
still has to be well-formed or compilation will fail.
If you want compilation to fail even if update
never gets called, you could use some type traits and a static_assert
(or some SFINAE hackery, if you need it) to ensure that func
is actually a pointer to a member function of T
:
template <typename T, typename U>
struct IsPointerToMemberOf : std::false_type {};
template <typename T, typename U>
struct IsPointerToMemberOf<T, U T::*> : std::true_type {};
template <typename T, typename U>
struct IsPointerToMemberFunctionOf
: std::integral_constant<
bool,
IsPointerToMemberOf<T, U>::value && std::is_member_function_pointer<U>::value
>
{};
template<typename T, auto func>
class EngineSystem
{
static_assert(IsPointerToMemberFunctionOf<T, decltype(func)>::value, "func must be a pointer to a member function of T");
//...
};
Live Demo
Related Topics
Multiple Definition of Inline Functions When Linking Static Libs
Unresolved External Symbol Lnk2019
Why Does Storing References (Not Pointers) in Containers in C++ Not Work
How to Make Elements of Vector Unique? (Remove Non Adjacent Duplicates)
Should We Generally Use Float Literals for Floats Instead of the Simpler Double Literals
So Why Is I = ++I + 1 Well-Defined in C++11
Passing Functor as Function Pointer
Overloading Base Class Method in Derived Class
Empirically Determine Value Category of C++11 Expression
Simulating Key Press Events in MAC Os X
Disambiguate Overloaded Member Function Pointer Being Passed as Template Parameter
Possible Problems with Nominmax on Visual C++
Is It Counter-Productive to Pass Primitive Types by Reference
Determine Path to Registry Key from Hkey Handle in C++
Doing a Static_Assert That a Template Type Is Another Template