result_of 没有为 mem_fn 定义类型
result_of does not define type for mem_fn
我有如下一段代码:
#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
只是 "would do the right thing"。谁能解释一下,这里发生了什么?
问题出在这里:
int get() const& {
// ^^^
您的成员函数 lvalue-reference 合格。在你的 Apply()
:
template<typename Func>
std::result_of_t<Func(X)> Apply(Func fn) {
return fn(X{});
}
您正在使用右值调用它。这给我们带来了这两个表达式之间的[令我非常惊讶]的区别:
X{}.get(); // ok
(X{}.*&X::get)(); // ill-formed
在特别是 pointer-to-member 运算符上,成员指针的ref-qualifiers 会根据对象的值类别进行检查。来自 [expr.mptr.oper]:
In a .*
expression whose object expression is an rvalue, the program is ill-formed if the second operand is a pointer to member function with ref-qualifier &
. In a .*
expression whose object expression is an lvalue, the
program is ill-formed if the second operand is a pointer to member function with ref-qualifier &&
.
所以第一个表达式没问题,get()
是 const&
限定的,但右值可以绑定到它。第二个表达方式不行——规则只是明确禁止它。
所以你看到的行为是完全正确的 - mem_fn
是通过直接调用成员函数定义的,它是 ill-formed 右值,所以 Apply
从重载中删除放。如果不是,那么实例化主体将是一个硬错误。
lambda 起作用的原因是临时 X
绑定到 lambda 的引用参数。 get()
然后在左值函数参数上调用 - 而不是在传递给它的临时参数上。但即使没有它,直接在临时对象上调用 get()
仍然没问题。
我有如下一段代码:
#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
只是 "would do the right thing"。谁能解释一下,这里发生了什么?
问题出在这里:
int get() const& {
// ^^^
您的成员函数 lvalue-reference 合格。在你的 Apply()
:
template<typename Func>
std::result_of_t<Func(X)> Apply(Func fn) {
return fn(X{});
}
您正在使用右值调用它。这给我们带来了这两个表达式之间的[令我非常惊讶]的区别:
X{}.get(); // ok
(X{}.*&X::get)(); // ill-formed
在特别是 pointer-to-member 运算符上,成员指针的ref-qualifiers 会根据对象的值类别进行检查。来自 [expr.mptr.oper]:
In a
.*
expression whose object expression is an rvalue, the program is ill-formed if the second operand is a pointer to member function with ref-qualifier&
. In a.*
expression whose object expression is an lvalue, the program is ill-formed if the second operand is a pointer to member function with ref-qualifier&&
.
所以第一个表达式没问题,get()
是 const&
限定的,但右值可以绑定到它。第二个表达方式不行——规则只是明确禁止它。
所以你看到的行为是完全正确的 - mem_fn
是通过直接调用成员函数定义的,它是 ill-formed 右值,所以 Apply
从重载中删除放。如果不是,那么实例化主体将是一个硬错误。
lambda 起作用的原因是临时 X
绑定到 lambda 的引用参数。 get()
然后在左值函数参数上调用 - 而不是在传递给它的临时参数上。但即使没有它,直接在临时对象上调用 get()
仍然没问题。