最近,我正在编写类似引用的代理类。我试图尽可能地使这个类真正像引用一样,尽管我仍然在发现它不能的新情况(例如,与auto,life extension等的不良交互)。似乎不可能在当前的语言规范中创建一个完全类似引用的代理类。
无论如何,我仍然试图让我的课程看起来像是大多数情况的真实参考。让我困惑的一件事是const-correctness。 似乎是一个非常成熟的建议,使“引用”和“引用到const”单独的类通过一些转换关系连接在一起。但是我应该为“const reference”做些什么呢?
似乎相对明显的是,“reference-to-const”代理和“const reference-to-const”代理之间应该没有区别。但是可变参考呢?
(1)“const reference”的行为应该像“reference-to-const”或
(2)const和非const代理之间应该没有区别吗?
我认为在这种情况下,const和非const代理之间应该没有区别,因为这个constness适用于代理本身,而不适用于“引用对象”。但是,似乎一些众所周知的代理类(std::vector<bool>::reference
和boost::multi_array_ref
)的例子并不像那样; const代理的行为有点像const-to-const。它们似乎可归类为案例(1)。
我现在越来越相信(1)应该是正确的选择,但我不太相信,因为我相信C ++中的“引用”只是表示不可空的const指针的语法糖。因为引用是“已经const”,所以const和非const限定代理之间应该没有区别。作为(2)的支持证据,允许使用以下代码:
struct A {
int& x;
};
int main() {
int x;
A const a{ x };
a.x = 10; // now, x above becomes 10
}
此处,a
的常量不适用于({1}}引用的对象。
“const和非const限定之间没有区别”意味着,我认为,代理类的每个成员函数都应该被限定为const,包含复制/移动赋值运算符。例如,如果我们选择遵循(2),则复制赋值运算符应该看起来像
a.x
并且Proxy const& Proxy::operator=(Proxy const& that) const/*?!*/ {
// assign referred-to-objects
return *this;
}
看起来真的很陌生。此外,如果我们选择遵循(2),可能会出现以下问题:
const
这些可被视为(1)的支持证据。
P.S。作为一个(可能不是)相关的主题,我发现将代理对象的ref-qualifier视为参与折叠规则的行为似乎很自然。也就是说,如果我的代理旨在表示左值引用,则ref-qualifier没有任何作用。但是,如果我的代理旨在表示右值引用,则左值代理应该像左值引用,而右值代理应该像右值引用一样。 根据此规则,我们会得到以下行为:
ProxyReturningContainer c;
for (auto const& x : c) // may expect reference-to-const, but gets mutable reference
{
// do something with x
// fortunately (?), x is not a dangling reference due to lifetime extension
}