2

I want to create the following class, but the compiler gives an error (it tells that the signatures of the methods are the same):

struct entities_set_less { constexpr bool operator()(const ContentEntity*& _Left, const ContentEntity*& _Right) const { // apply operator< to operands return (_Left < _Right); } constexpr bool operator()( const const ContentEntity*& _Left, const const ContentEntity*&_Right) const { // apply operator< to operands return (_Left < _Right); } }; 

From my point of view, an expression like const const ContentEntity*& means "const reference to pointer on const ContentEntity". It should be different from const ContentEntity*&, which is just "const reference to pointer on non const type".

10
  • 1
    Maybe: const ContentEntity* const& _Left Commented May 16, 2022 at 14:48
  • 1
    const ContentEntity*& is a non-const reference to pointer to const ContentEntity. Commented May 16, 2022 at 14:49
  • 2
    const const T*& is not const (const T*)&, it is (const const T)*&; the const is duplicated so one of them is ignored. Commented May 16, 2022 at 14:56
  • 1
    Nope: they are the same. From MSVC: warning C4227: anachronism used: qualifiers on reference are ignored. From clang: error : 'const' qualifier may not be applied to a reference. Commented May 16, 2022 at 15:05
  • 1
    Note that const int& is a reference to a const int. But int& const would be an attempt at a const reference to a (non-const) int. Commented May 16, 2022 at 15:06

3 Answers 3

2

First, let's clarify (or attempt to) what you actually want. You say you want a "const reference" … but references are (effectively) const, anyway (i.e., once a reference variable is bound to its target, it cannot subsequently be bound to a different target).

So, what you may have meant is that you want the arguments in the second overload to be references to constant pointers to constant objects; that is, neither the pointers nor the objects can be modified (in your first overload, the pointed-to objects cannot be modified but the referred-to pointers can be.

To make the pointers const, you need to add that keyword immediately after the pointer indicator (*). Like this:

struct entities_set_less { constexpr bool operator()(const ContentEntity*& _left, const ContentEntity*& _light) const { // references to non-const pointers to const objects return (_left < _light); } constexpr bool operator()(const ContentEntity* const& _left, const ContentEntity* const& _right) const { // references to CONST pointers to const objects return (_left < _right); } }; 

Note that I have also changed your _Left and _Right identifiers to _left and _right, because IDs starting with an underscore followed by an uppercase letter are reserved. From this C++17 Draft Standard:

5.10 Identifiers       [lex.name]


(3.1)     — Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.

Sign up to request clarification or add additional context in comments.

Comments

2

I believe a lot of confusion about what the const applies to can be removed by adopting the east-const convention:

const reference to pointer on const ContentEntity

ContentEntity const* const& 

const reference to pointer on non const type

ContentEntity* const& 

This way, you know that the const always refers to what's on its left.

Also, when in doubt, I usually check on cdecl the type of the variables I'm declaring.

1 Comment

If the const refers to what's on its left then why do you not put a space on the right. Make the visual match the binding: ContentEntity const *const &ref. Not sure why you find this more confusing: const ContentEntity *const &ref.
1

const const is never correct. The rule to remember is that const applies to whatever is on its left. The exception is when const is the leftmost token, in which case it applies to the right. So, when you want to add const, add it to the right side of whatever you want to be const.

How to create const reference to pointer on const?

So, let's start with a reference to a pointer:

ContentEntity*& 

We want it to be a reference to a const pointer. We place const to the right of *. Since it applies to left, this means that the referred pointer is const:

ContentEntity* const & 

We want it to be a const pointer to const object of type ContentEntity. We place const to the right of ContentEntity. Since it applies to left, this means that the pointed ContentEntity is const:

ContentEntity const * const & 

Alternatively, since ContentEntity is the first token, we can place its const to the left:

const ContentEntity * const & 

All that said, it's quite rare to explicitly use a reference to const a pointer. It's more typical to pass a copy of the reference. References to const pointers do occur often when instantiating templates.

4 Comments

position of const plays role. You missed the case const ContentEntity* - it's pointer to const type. it's not equalent to ContentEntity* const which simply means const pointer
Hmm. Correct insofar as it goes. But it doesn't address the issue that a class can't have two functions that differ only in one taking non-const refs and the other taking const refs. Can't have both bool foo(int& a, int& b) and bool foo(int& const a, int& const b).
@LmTinyToon Well, you didn't want a reference to non-const pointer, so I didn't feel the need to show that.
@AdrianMole You cannot have int& const at all because you aren't allowed to add cv-qualifiers to references. You can add cv-qualifiers to the referred type, and you can have both bool foo(int& a, int& b) and bool foo(int const& a, int const& b) overloads.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.