Consider three ways to implement a routine in c++: through functors, member functions, and non-member functions. For example,
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
class FOO
{
public:
void operator() (string word) // first: functor
{
cout << word << endl;
}
void m_function(string word) // second: member-function
{
cout << word << endl;
}
} FUNCTOR;
void function(string word) // third: non-member function
{
cout << word << endl;
}
Now consider a template-function to call the three functions above:
template<class T>
void eval(T fun)
{
fun("Using an external function");
}
What is the proper way to call FOO::m_function
through eval?
I tried:
FUNCTOR("Normal call"); // OK: call to ‘void FOO::operator()(string)‘
eval(FUNCTOR); // OK: instantiation of ‘void eval(T) [with T = FOO]’
function("Normal call"); // OK: call to ‘void function(string)’
eval(function); // OK: instantiation of ‘void eval(T) [with T = void (*)(string)]’
FUNCTOR.m_function("Normal call"); // OK: call to member-function ‘FOO::m_function(string)’
eval(FUNCTOR.m_function); // ERROR: cannot convert ‘FOO::m_function’ from type
// ‘void (FOO::)(std::string) {aka void (FOO::)(string)}’
// to type ‘void (FOO::*)(std::basic_string<char>)’
// In instantiation of ‘void eval(T) [with T = void (FOO::*)(string)]’:
// ERROR: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘fun (...)’, e.g. ‘(... ->* fun) (...)’
The term member template refers to both member function templates and nested class templates. Member function templates are function templates that are members of a class or class template. Member functions can be function templates in several contexts.
A member function template cannot be virtual, and a member function template in a derived class cannot override a virtual member function from the base class.
To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.
To pass an object as an argument we write the object name as the argument while calling the function the same way we do it for other variables. Syntax: function_name(object_name); Example: In this Example there is a class which has an integer variable 'a' and a function 'add' which takes an object as argument.
A pointer to member function and a pointer to function are two different beasts. The former takes an implicit first argument, the this
pointer, or in other words, a pointer to the instance on which the member function is to be invoked on.
Typically, in order to be able to pass the member function as a callable object, you bind
the instance on which it is to be invoked on, and then use placeholders
to indicate arguments that will be passed to the callable later. In your case
eval(std::bind(&FOO::m_function, &FUNCTOR, std::placeholders::_1));
The first argument to bind
above is the pointer to member function that you want to invoke, and the second is a pointer to the FOO
instance on which you want to invoke m_function
. The last one is a placeholder that indicates the first argument passed to the callable created by bind
should be used when calling the member function.
Another way to do this is to pass a lambda expression to eval
that takes a char const *
(or std::string const&
) argument and calls the member function.
eval([](char const *c) { FUNCTOR.m_function(c); });
Live demo
Inside eval
, you cannot call a member function because you don't have any object;
you may go for this:
template<class T, class U>
void eval(T&& object, U fun)
{
(object.*fun)("Using an external function");
}
and then
eval(FUNCTOR, &FOO::m_function);
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