由于错误,我在原型的末尾有一个&
(请参见下面的示例)。 gcc和Clang都没有抱怨。我注意到生成的符号并不完全相同。
示例:
class A
{
public:
void fn() &
{
return;
}
};
int main()
{
A a;
a.fn();
return 1;
}
不带&
:_ZN1A2fnEv
和带&
:_ZNR1A2fnEv
的符号名称。
是什么意思?我想念什么吗?
谢谢
答案 0 :(得分:8)
成员函数声明末尾的&
是 ref限定符。它适用于调用成员函数的对象值,并限制该值的值类别:
&
限定符的函数只能在左值上调用。&&
限定符的函数只能在右值上调用。ref限定符会影响重载分辨率,例如实例值不匹配的重载是不可行的。
标准库使用的引用限定符不多(我只能想到std::optional
),所以让我们来编写自己的示例:
struct X {
explicit X(int n) : s_(n, 'a') {}
std::string s_;
const char* f1() const { return s_.c_str(); }
const char* f2() const & { return s_.c_str(); }
const char* f3() const && { return s_.c_str(); }
};
现在考虑以下呼叫:
int main() {
X x(10);
x.f1(); // OK
X(20).f1(); // OK
x.f2(); // OK
X(20).f2(); // ill-formed
x.f3(); // ill-formed
X(20).f3(); // OK
}
该示例还演示了此功能为何有用的原因:当成员函数返回对对象本身内部某些部分的引用时,重要的是,该内部引用不会超过对象的生命周期。如果您的成员函数不合格,则可以很容易地引入生命周期错误。例如:
const char* s = std::string("abcde").c_str(); // dangling pointer!
一种改进此类“内部状态访问” API的方法是为不同的ref限定的重载创建不同的返回值(类别)。要回到std::optional
,参与访问本质上可以归结为这组重载:
struct MyOptional {
T value_; // assume engaged!
T& get() & { return value_; }
T&& get() && { return std::move(value_); }
};
这意味着MyOptional::get
在左值可选上调用时返回左值,而在右值上调用时返回右值(实际上是xvalue)。这意味着,在给定MyOptional x;
的情况下,允许绑定T& r = x.get();
,但不允许绑定T& r = MyOptional().get();
,类似地,禁止T&& r = x.get();
,但允许T&& r = std::move(x).get()
。 / p>