4

我有一个带有默认参数的成员函数的类。

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 被采用不同参数的成员重载时,我也有同样的问题......

4

2 回答 2

5

默认函数在调用时绑定,但不能隐式绑定到任何类型的包装器中,因为它们的实现方式。当你通过时&Class::membermem_fn只看到一个void (Class::*)(int),而看不到默认参数。使用tr1::bind,您可以显式地绑定默认参数:std::tr1::bind(&Class::member, 0)或者您可以像使用它一样使用它mem_fn,但您不能在一个对象中同时执行这两种操作。您必须为此编写自己的包装类。

至于重载,您必须显式指定模板参数,mem_fn以便选择正确的函数指针,如mem_fn<void(int)>(&Class::member).

于 2008-11-16T19:41:42.543 回答
3

原因是任何默认参数都不会改变函数的函数类型。

mem_fn无法知道该函数只需要 1 个参数,或者该函数的第二个参数是可选的,因为它获得的所有知识都是由&Class::member( 保留void(Class::*)(int)) 的类型提供给它的。因此它需要一个整数作为第二个参数。

如果要传递重载成员函数的地址,则必须强制转换为正确的成员函数指针类型:

static_cast<void(Class::*)()>(&Class::member) 而不是 just &Class::member,所以编译器有一个上下文来确定要采用哪个地址。

编辑: coppro 有一个更好的解决方案如何提供上下文:std::tr1::mem_fn<void()>(&Class::member)

于 2008-11-16T19:36:27.450 回答