result_of没有为mem_fn定义类型

时间:2017-02-08 12:58:17

标签: c++ c++14 member-function-pointers result-of

我有以下代码:

#include <functional>

struct X {
    int get() const& {
        return 42;
    }
};

template<typename Func>
std::result_of_t<Func(X)> Apply(Func fn) {
    X x;
    return fn(x);
}

int main(void) {
    Apply([](X const& x){return x.get();});
    //Apply(std::mem_fn(&X::get)); // does not compile
}

第一次调用Apply编译正常,但如果我取消注释第二次调用,则会出现以下编译错误:

main.cpp:16:5: error: no matching function for call to 'Apply'
    Apply(std::mem_fn(&X::get)); // does not compile
    ^~~~~
main.cpp:10:27: note: candidate template ignored: substitution failure [with Func = std::_Mem_fn<int (X::*)() const &>]: no type named 'type' in 'std::result_of<std::_Mem_fn<int (X::*)() const &> (X)>'
std::result_of_t<Func(X)> Apply(Func fn) {
                          ^

我不知何故预计这两个电话都可以互换使用,而std::mem_fn只会&#34;做正确的事情&#34;。任何人都可以解释一下,这里会发生什么?

1 个答案:

答案 0 :(得分:7)

问题在于:

int get() const& {
//            ^^^

您的会员功能是左值参考限定。在Apply()

template<typename Func>
std::result_of_t<Func(X)> Apply(Func fn) {
    return fn(X{});
}

你用rvalue调用它。这让我们看到了这两个表达式之间[令我非常惊讶的]差异:

X{}.get();        // ok
(X{}.*&X::get)(); // ill-formed

特定指向成员的操作符上,将根据对象的值类别检查成员指针的ref限定符。来自[expr.mptr.oper]:

  

在对象表达式为右值的.*表达式中,如果第二个操作数是指向 ref-qualifier &的成员函数的指针,则程序格式错误。在对象表达式为左值的.*表达式中,   如果第二个操作数是指向具有ref-qualifier &&的成员函数的指针,则程序格式错误。

所以第一个表达式没问题,get()const& - 限定但是rvalues可以绑定到它。第二个表达式不合适 - 规则只是明确禁止它。

所以你看到的行为是完全正确的 - mem_fn是通过直接调用在rvalue上形成错误的成员函数来定义的,因此从重载集中删除了Apply。如果不是,那么实例化身体将是一个很难的错误。

lambda工作的原因是临时X绑定到lambda的引用参数。然后在lvalue函数参数上调用get() - 而不是传递给它的临时函数。但即使没有这个,直接在临时上调用get()仍然可以。