将成员函数作为参数传递给函数模板
passing member-function as argument to function-template
考虑在 C++ 中实现例程的三种方法:通过仿函数、成员函数和非成员函数。例如,
#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;
}
现在考虑调用上述三个函数的模板函数:
template<class T>
void eval(T fun)
{
fun("Using an external function");
}
通过 eval 调用 FOO::m_function
的正确方法是什么?
我试过了:
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) (...)’
在eval
里面,你不能调用成员函数,因为你没有任何对象;
你可以这样做:
template<class T, class U>
void eval(T&& object, U fun)
{
(object.*fun)("Using an external function");
}
然后
eval(FUNCTOR, &FOO::m_function);
指向成员函数的指针和指向函数的指针是两种不同的东西。前者接受一个隐含的第一个参数,即 this
指针,或者换句话说,一个指向调用成员函数的实例的指针。
通常,为了能够将成员函数作为可调用对象传递,您 bind
the instance on which it is to be invoked on, and then use placeholders
指示稍后将传递给可调用对象的参数。你的情况
eval(std::bind(&FOO::m_function, &FUNCTOR, std::placeholders::_1));
上面 bind
的第一个参数是指向要调用的成员函数的指针,第二个是指向要调用的 FOO
实例的指针 m_function
.最后一个是占位符,表示在调用成员函数时应使用传递给 bind
创建的可调用对象的第一个参数。
另一种方法是将 lambda 表达式传递给 eval
,它接受 char const *
(或 std::string const&
)参数并调用成员函数。
eval([](char const *c) { FUNCTOR.m_function(c); });
考虑在 C++ 中实现例程的三种方法:通过仿函数、成员函数和非成员函数。例如,
#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;
}
现在考虑调用上述三个函数的模板函数:
template<class T>
void eval(T fun)
{
fun("Using an external function");
}
通过 eval 调用 FOO::m_function
的正确方法是什么?
我试过了:
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) (...)’
在eval
里面,你不能调用成员函数,因为你没有任何对象;
你可以这样做:
template<class T, class U>
void eval(T&& object, U fun)
{
(object.*fun)("Using an external function");
}
然后
eval(FUNCTOR, &FOO::m_function);
指向成员函数的指针和指向函数的指针是两种不同的东西。前者接受一个隐含的第一个参数,即 this
指针,或者换句话说,一个指向调用成员函数的实例的指针。
通常,为了能够将成员函数作为可调用对象传递,您 bind
the instance on which it is to be invoked on, and then use placeholders
指示稍后将传递给可调用对象的参数。你的情况
eval(std::bind(&FOO::m_function, &FUNCTOR, std::placeholders::_1));
上面 bind
的第一个参数是指向要调用的成员函数的指针,第二个是指向要调用的 FOO
实例的指针 m_function
.最后一个是占位符,表示在调用成员函数时应使用传递给 bind
创建的可调用对象的第一个参数。
另一种方法是将 lambda 表达式传递给 eval
,它接受 char const *
(或 std::string const&
)参数并调用成员函数。
eval([](char const *c) { FUNCTOR.m_function(c); });