Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can C++ const references be collasped into non-const references

Consider the following C++ program:

#include <iostream>

template<typename T>
class A
{
public:
    explicit A(T& x) : x_(x){}
    const T& get() { return x_; }

private:
    T x_;
};

int main()
{
    int x = 42;
    A<int&>(x).get() = 43; // compiles fine, even though get() looks like it returns a const ref
    std::cout << x << '\n';
}

The program compiles OK and outputs 43. This suggests that the seemingly const reference returned by get() is in fact a non-const reference, because it allows to modifies the value it refers to.

Is it a rule of reference collapsing that causes this behaviour?

How to enforce that the reference returned from get() behaves like a const reference, that is, it doesn't allow to modify the value it refers to?

like image 354
Jonathan Boccara Avatar asked May 14 '18 17:05

Jonathan Boccara


1 Answers

Is it a rule of reference collapsing that causes this behaviour?

Yes. You have:

T = int&
const T& = const (int&) &

References can't be const (you can't rebind them anyways, so it's ignored) and a reference to a reference is just a reference.

So you have

const T& = int&

To fix this, you need to apply const to the underlying type, which you can do like this by removing the reference:

const std::remove_reference_t<T>& get() { return x_; }
//    ^^^^^^^^^^^^^^^^^^^^^^^
like image 147
Rakete1111 Avatar answered Sep 21 '22 09:09

Rakete1111