3

Recently, I'm writing a reference-like proxy class. I'm trying to make this class really reference-like as much as possible, though I'm still discovering a new situation where it can't (e.g., bad interaction with auto, lifetime extension, and others). It seems that it is just impossible to make a perfectly reference-like proxy class in the current specification of the language.

Anyway, I'm still trying to make my class looks like a real reference for most of the situations. One thing that confuses me right now is const-correctness. It seems to be a quite established advice to make "reference" and "reference-to-const" separate classes that are connected together by some conversion relations. But what should I do for "const reference"?

It seems relatively obvious that there should be no difference between "reference-to-const" proxy and "const reference-to-const" proxy. But what about mutable reference?

(1) Should a "const reference" behave like "reference-to-const", or

(2) There should be no difference between const and non-const proxies?

I've thought that also in this case there should be no difference between const and non-const proxies because this constness applies to the proxy itself, not to the "referred object". However, it seems that some well-known examples of proxy classes (std::vector<bool>::reference and boost::multi_array_ref) do not act like that; const proxies behave somewhat like reference-to-const. It seems they can be classified as the case (1).

I'm now increasingly believing that (1) should be the right choice, but I'm not quite convinced because I've believed "reference" in C++ is just a syntactic sugar for representing non-nullable const pointer. Because a reference is "already const", there should be no difference between const and non-const qualified proxies. As a supporting evidence for (2), the following code is allowed:

struct A {
    int& x;
};

int main() {
    int x;
    A const a{ x };
    a.x = 10;  // now, x above becomes 10
}

Here, constness of a does not applies to (the object referred by) a.x.

"No difference between const and non-const qualification" implies, I think, EVERY member function of the proxy class should be qualified as const, INCLUDING copy/move assignment operators. For example, if we choose to follow (2), the copy assignment operator should look like

Proxy const& Proxy::operator=(Proxy const& that) const/*?!*/ {
    // assign referred-to-objects
    return *this;
}

and that const looks really unfamiliar. Also, if we choose to follow (2), there may be a problem like the following:

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
}

These may be regarded as supporting evidences for (1).


P.S. As a (possibly not) related topic, I've figured out that it seems very natural to treat ref-qualifier of a proxy object as something that acts like the reference collapsing rule. That is, if my proxy is intended to represent lvalue references, then ref-qualifier has no role. However, if my proxy is intended to represent rvalue references, then an lvalue proxy should act like an lvalue reference, while an rvalue proxy should act like an rvalue reference. From this rule, we get the following behavior:

void f(int&& x) {
    // inside f, x is now an lvalue; we should write std::move(x) in order to get rvalues
}
Junekey Jeon
  • 1,496
  • 1
  • 11
  • 18
  • It's typically easier to read if you put const before the type, like so: "const A& a" – user997112 Mar 19 '18 at 10:20
  • 2
    @user997112 [Opinion-based](https://stackoverflow.com/questions/5503352). The 2nd & 3rd most voted answer prefer `A const`. – user202729 Mar 19 '18 at 12:01
  • Usually, one should follows rule (1). So for example, your proxy would works the same way a vector of 1 item would. That is, if you have constant vector or reference to one, you cannot change the item. Rule (2) have its uses but should not be the one taken by default. – Phil1970 Mar 21 '18 at 02:38
  • @Phil1970 Why a proxy should work like a vector of one item? I think the latter is clearly a value type, not a proxy (reference-like) type. – Junekey Jeon Jun 18 '18 at 12:12

0 Answers0