为什么可以在临时但全局函数上调用成员函数?

edA*_*a-y 5 c++ language-lawyer

在下面的代码中,我将其step称为成员函数,并将其作为临时值的全局函数.成员函数是允许的,并且有效,而全局函数由于不允许而被禁止invalid initialisation of non-const reference of type ‘kludge&’ from an rvalue of type ‘kludge’.

从语言的角度来看,我试图理解为什么允许一种行为而另一种行为不允许.从技术上讲,调用和函数似乎都是相同的编译,或者至少可以编译.

#include <iostream>

struct kludge {
    int a;
    kludge() {
        a = 1;
    }

    kludge & step() {
        a++;
        std::cout << a << ",";
        return *this;
    }
};

kludge get() {
    kludge t;
    return t;
}

kludge & step( kludge & t ) {
    t.a++;
    std::cout << t.a << ",";
    return t;
}

int main() {
    get().step();
    step( get() );
}
Run Code Online (Sandbox Code Playgroud)

Col*_*mbo 6

您不能将rvalues绑定到非const左值引用1.这适用于step(get())作为step非const左值引用的参数,不能绑定到prvalue(纯rvalue)get().

但是,成员函数本身可以在每个值类别的对象参数上调用,无论是左值还是右值 - [over.match.funcs]/4和/ 5:

对于非静态成员函数,隐式对象参数的类型是

  • "左值参考CV X "为没有声明的函数REF-限定符或与& REF-限定符

[..]

对于未使用ref-qualifier声明的非静态成员函数,应用其他规则:

  • 即使隐式对象参数不是const-qualified,也可以将rvalue绑定到参数,只要在所有其他方面,参数可以转换为隐式对象参数的类型. [ 注意:这样的参数是一个rvalue的事实不会影响隐式转换序列的排名(13.3.3.2).- 结束说明 ]

但是,如果使用所谓的ref-qualifiers,则可以限制对特定成员函数有效的值类别.也就是说,如果你写:

kludge & step() & { /* .. */ }
Run Code Online (Sandbox Code Playgroud)

电话会议get().step()也是不正确的.


1)
这是一个众所周知的事实,但这里是[dcl.init.ref]/5,大大缩短了:

参考输入" CV1 T1 "是通过类型"的表达初始化CV2 T2 "如下:

  • 如果引用是左值引用和初始化表达式
    • 是左值[..]
    • 有一个类类型(即,T2是一个类类型),其中T1与引用无关T2,并且可以隐式转换为类型为" cv3 T3 " 的左值,[...]

  • 否则,引用应是对非易失性const类型的左值引用(即,cv1应为const),或者引用应为右值引用.


P0W*_*P0W 1

临时不能绑定到非常量引用

step( get() );
//    ~~~~~   Creates a temporary object (r-value)
// But step( ) excepts a non-const reference
Run Code Online (Sandbox Code Playgroud)