为什么没有指向成员函数的隐式转换

3

在使用std::bind时,我发现对于成员函数,需要加上&才能获得其地址,而对于普通函数则不需要,例如:

class Obj{
public:
    void member_func(int val);
};

void func(int val);

int main(){
    Obj obj;
    auto mf1 = std::bind(&Obj::member_func, &obj, 1); // ok
    auto mf2 = std::bind(Obj::member_func, &obj, 1); // error
    
    auto f1 = std::bind(&func, 1); // ok
    auto f2 = std::bind(func, 1); // ok
}

在进行STFW(搜索友好的网页 :) )之后,我在cpp reference中找到了以下内容:

T 类型的函数类型的 lvalue 可以被隐式转换为指向该函数的 prvalue 指针。这不适用于非静态成员函数,因为引用非静态成员函数的 lvalue 不存在。

这解释了为什么成员函数需要使用 &,但我仍然不完全理解为什么没有对成员函数指针进行隐式转换?

特别是,“引用非静态成员函数的 lvalue 不存在”是什么意思?

"函数类型的 lvalue" 也让我感到困惑,这是不是意味着函数标识符 func 是一个 lvalue?

第一次提问,希望我已经清晰地表达了我的问题。


3
那个引用几乎是从标准中直接摘录的。至于为什么,我认为这个评论解释得相当清楚。(链接在此:https://stackoverflow.com/questions/37501982/address-operator-with-pointer-to-member-function#comment62498961_37501982) - ixSci
2个回答

4
我仍然不完全理解为什么没有将成员函数隐式转换为指针的方式。这主要是为了防止您犯下如下错误:
if (MyClass::MyFunc) ...                    // oops! would always be true, if legal

当你本意要输入时:
if (MyClass::MyFunc ()) ...
//                  ^^

这其实是一件好事™。

但这也引出了一个问题,为什么普通函数不能像这样工作呢?毕竟,下面这段代码虽然毫无意义,但完全合法:

if (MyNonMemberFunc) ...                    // oops! always true, rats!

这是对C语言的回溯,如果你省略括号,函数名会衰变为指针。这样做是有价值的,但总体来说,我认为大多数人都希望正确性而不是必须在意图上添加前导&符号。
因此,我们有不同的规则适用于成员函数和非成员函数,这有点不幸,但标准委员会显然想要修复成员函数的这个陷阱,但不能为非成员函数,以保持向后兼容性。公平起见,大多数现代编译器确实会警告你如果你写if (MyNonMemberFunc),所以考虑到所有事情,我们并不处于一个很糟糕的地方。

你的回答是一个猜测。我不认为这是真正的原因。特别是真正的原因(正如我在我的回答中所解释的那样)是成员指针与类型指针不同,而且除了静态成员指针之外,涉及“指针”的文本不适用于成员指针这意味着它们应该被区别对待。这就是为什么我们必须明确地使用 & 来强调它们是与类型指针不同的类型。 - Jason
请不要误解,@anoop,但我在你身上看到了很多年轻的自己。 - Paul Sanders
(只是让你知道,不是我给你点了踩。) - Paul Sanders
我明白了,我以为你在我的回答下面点了踩并解释了原因。但事实并非如此。除了历史原因(如你所解释的),我还认为有一个事实上的原因(如我所解释的)不允许在这种情况下进行隐式转换。特别是,我认为我在答案中引用标准中的陈述可以逻辑上用来回答手头的问题,就像我在答案中所做的那样。 - Jason
很高兴您能以本意理解这句话。我们可以说,答案是互相补充的 :) - Paul Sanders
显示剩余2条评论

0
为什么没有成员函数指针的隐式转换?
非静态成员函数指针实际上不是指针,这可以从标准中以下语句看出:
来自dcl.mptr#3's note:
[注: 另请参见 [expr.unary] 和 [expr.mptr.oper]。"成员指针" 类型与 "指针" 类型不同,即只能通过成员指针声明符号语法声明成员指针,而不能通过指针声明符号语法声明成员指针。C++ 中没有 "成员引用" 类型。 ——end note]
并且来自basic.compound#3
除了指向静态成员的指针外,“指针”一词不适用于成员指针...
(我强调)
上述两个引用语句的组合说明了为什么我们需要如下所述使用&来指向成员函数的指针。
请注意上述引用语句中的突出部分(“distinct type”)。由于成员指针是一种独特的类型,并且涉及指针的文本不适用于成员指针,这意味着它们应该被区别对待。这就是为什么我们需要明确添加&来强调它们与类型指针的不同之处的原因。

现在来到你的第二个问题:

"引用非静态成员函数的 lvalues 不存在" 是什么意思?

标准特别指出(在上面引用的同一注释中):

C++ 中没有 "成员引用" 类型。


1
重复标准而不做任何解释,特别是不涉及OP的问题...对我来说,这样做似乎无助于回答OP所问的任何问题... - Klaus
1
@Klaus 我的回答第一行解释了为什么没有隐式转换。特别是因为a)成员函数指针不是指针,b)标准规定“除了静态成员指针外,指向‘指针’的文本不适用于成员指针”,并且标准明确指出“这不适用于非静态成员函数,因为引用非静态成员函数的lvalue不存在。”。我回答中引用的所有语句都与OP的问题相关。 - Jason
1
为什么没有指向成员函数的隐式转换? - Klaus
1
@Klaus 因为标准这么规定了?你是在问为什么标准要这样规定吗? - Jason
1
“你在问为什么标准会这样规定吗?” 是的,他正在问(显然)。我也是这样想的。 - Paul Sanders
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接