我有一个带有成员函数的类,它接受一个默认参数。
struct Class
{
void member(int n = 0)
{}
};
通过std :: tr1 :: mem_fn我可以调用它:
Class object;
std::tr1::mem_fn(&Class::member)(object,10);
那就是说,如果我想用默认参数调用对象上的可调用成员,那么正确的语法是什么?
std::tr1::mem_fn(&Class::member)(object); // This does not work
g ++抱怨以下错误:
test.cc:17: error: no match for call to ‘(std::tr1::_Mem_fn<void (Class::*)(int)>) (Class&)’
/usr/include/c++/4.3/tr1_impl/functional:551: note: candidates are: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class&, _ArgTypes ...) const [with _Res = void, _Class = Class, _ArgTypes = int]
/usr/include/c++/4.3/tr1_impl/functional:556: note: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class*, _ArgTypes ...) const [with _Res = void, _Class = Class, _ArgTypes = int]
但是,当Class :: member被带有不同参数的成员重载时,我遇到了同样的问题...
答案 0 :(得分:5)
默认函数在调用时绑定,但由于它们的实现方式,无法隐式绑定到任何类型的包装器。当您通过&Class::member
时,mem_fn
只会看到void (Class::*)(int)
,并且无法看到默认参数。使用tr1::bind
,您可以明确地绑定默认参数:std::tr1::bind(&Class::member, 0)
或者您可以像mem_fn
那样使用它,但是您不能在一个对象中同时使用它。你必须为此编写自己的包装类。
对于重载,您必须显式指定mem_fn
的模板参数,以便在mem_fn<void(int)>(&Class::member)
中选择正确的函数指针。
答案 1 :(得分:3)
原因是任何默认参数都不会更改函数的函数类型。
mem_fn
无法知道函数只需要1个参数,或者函数的第二个参数是可选的,因为它获得的所有知识都是由&Class::member
的类型给出的(保持void(Class::*)(int)
)。因此,需要一个整数作为第二个参数。
如果要传递成员函数的地址重载,则必须转换为正确的成员函数指针类型:
static_cast<void(Class::*)()>(&Class::member)
而不仅仅是&Class::member
,因此编译器有一个上下文来确定要采用的地址。
修改:coppro有一个更好的解决方案如何提供上下文:std::tr1::mem_fn<void()>(&Class::member)