74

So, I realize that const T& and T const& are identical and both mean a reference to a const T. In both cases, the reference is also constant (references cannot be reassigned, unlike pointers). I've observed, in my somewhat limited experience, that most C++ programmers use const T&, but I have come across a few people who use T const&. I use const T& simply because I learned it that way, and so T const& looks a little bit funny to me. What is the reason that you use the variant that you use? Do any of you work at an organization for which the coding standards mandate the use of one variant over the other?

Edit
Based on the answers, it would appear that one reason for choosing between the two is whether you want to read it like the compiler (right-to-left) or like English (left-to-right). If one reads it like the compiler, then "T const&" reads as "& (reference) const (to a constant) T (of type T)". If one reads it like English, from left-to-right, then "const T&" is read as "a constant object of type T in the form of a reference". I prefer to read it like English prose, but I can certainly see the sense in interpreting it the way that the compiler does.

No one has answered the organization or coding standards question, but I strongly suspect that most organizations do not mandate one over the other, although they might strive for consistency.

Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200
  • 34
    The former is chosen by people who do it right, and the latter chosen by people who do it wrong. Just like how people who do it right put the opening brace on the same line, and people who do it wrong put it on its own line. – davr Apr 14 '10 at 19:40
  • 8
    @davr: I rofl'd. – GManNickG Apr 14 '10 at 19:43
  • 31
    Don't you mean the latter is by people who do it right, and the former by people who do it left? – Niki Yoshiuchi Apr 14 '10 at 19:44
  • @davr, ok, so it is purely "religious". Are people as serious about those two as they are about the choice of braces? I've seen coding standards mandate braces, but not the different reference types. – Michael Aaron Safyan Apr 14 '10 at 19:44
  • I say it aloud as "const reference to T" so if I could have it my way, it'd be `const& T`! – AshleysBrain Apr 14 '10 at 22:34
  • 1
    Yeah, I haven't really seen much controversy about one way or the other. But unlike brace style, const-first seems to be clearly the most common. – davr Apr 16 '10 at 05:13
  • 10
    @davr You hurt my feelings with the comment about the braces :( But code is so much more readable with an opening brace on its own line, IMO. – Tqn Jul 08 '14 at 07:24
  • 1
    Possible duplicate of [C++: const reference, before vs after type-specifier](https://stackoverflow.com/questions/3694630/c-const-reference-before-vs-after-type-specifier) – Ciro Santilli OurBigBook.com Nov 13 '18 at 19:16
  • 1
    `c++filt` uses `T const &` in its output. There can be no more definitive authority than that, so this is the official best way. :-) – greggo Nov 06 '19 at 23:23
  • I would say that "T const&" is like French, in which adj follows noun (in most cases). – bruin May 18 '20 at 13:56

10 Answers10

52

I think some people simply prefer to read the declarations from right to left. const applies to the left-hand token, except when there is nothing there and it applies on the right-hand token. Hence const T& involves the "except"-clause and can perhaps be thought more complicated (in reality both should be as easy to understand).

Compare:

const T* p;  (pointer to T that is const)
T const* p;  (pointer to const T) //<- arguable more natural to read
T* const p;  (const pointer to T)
UncleBens
  • 40,819
  • 6
  • 57
  • 90
  • 1
    @UncleBens, thanks. So it seems T const& is preferred by those who want to read it right-to-left like the compiler, and const T& is preferred by those who want to read it left-to-right like English. – Michael Aaron Safyan Apr 14 '10 at 19:57
  • Actually English often goes from right to left, e.g `a of b` whereas in other languages only `b's a` might be possible. (Which way things are natural to read is deeply subjective, perhaps also depending on language background, how analytic/synthetic your way of thinking is etc) – UncleBens Apr 14 '10 at 20:53
  • 1
    I take your meaning, but "a of b" is still read from left-to-right (you say {"ay", "of", "bee"} and not {"bee", "of", "ay"}), even though it is evaluated from right-to-left. – Michael Aaron Safyan Apr 14 '10 at 23:49
  • 3
    @Michael, albeit writing "T const" i still read declarations from left-to-right. So i say "T const" instead of "const T". – Johannes Schaub - litb Apr 17 '10 at 12:10
  • `...except when there is nothing there[...] Hence const T& involves the "except"-clause` Exactly. This is my reason for writing `T const&` which makes me feel quite alone, but I stand my ground. – v.oddou Mar 12 '15 at 02:32
  • 1
    "pointer to T that is const" - not clear from the wording whether T is const or the pointer is const... – einpoklum Dec 10 '15 at 09:22
31

This will make a difference when you have more then one const/volatile modifiers. Then putting it to the left of the type is still valid but will break the consistency of the whole declaratiion. For example:

T const * const *p;

means that p is a pointer to const pointer to const T and you consistenly read from right to left.

const T * const *p;

means the same but the consistency is lost and you have to remember that leftmost const/volatile is bound to T alone and not T *.

Tomek
  • 4,554
  • 1
  • 19
  • 19
  • 8
    It might also make a difference if someone does `T const` and then someone else comes along who does `const T`, and accidentally changes something to say: `const T const * const p`, to which the compiler replies `error: Just how const do you want it to be?` – greyfade Apr 14 '10 at 22:55
  • @greyfade, haha, I had heard about that error, though have never seen it in person... which compiler is it? – Michael Aaron Safyan Apr 14 '10 at 23:52
  • @Michael Aaron Safyan: I think I managed to get GCC to spit it out once, but I honestly don't remember and haven't reproduced it. – greyfade Apr 15 '10 at 03:45
7

If you find this discussion interesting, you'd probably find this article by Dan Saks interesting. It doesn't directly address your question, but explains why he prefers

VP const foo[];

to

const VP foo[];

It's because given

typedef void *VP;

you could easily be misled into thinking that the second example above means

const void *foo[];  // Wrong, actually: void *const foo[];

but the first example is harder to misinterpret.

Larry Engholm
  • 370
  • 1
  • 6
  • 1
    +1 for the link to the article, but I think You got it backwards in Your post. Both "VP const foo[];" and "const VP foo[];" actualy do mean "void *const foo[];". Check the article again. – Maciej Hehl May 28 '10 at 16:03
  • Thanks for the correction. You'd be led into thinking that the first example means what it actually means (which is why he prefers it), and misled into thinking that the second example means const void *foo[]; – Larry Engholm May 28 '10 at 16:46
5

My reasoning is as follows:

It does seem to roll off the tongue better if you write "const T&" but when you do that you end up with the ambiguous, "constant T reference." I've seen this cause problems more than once in the understandability of code that allowed someone, even semi-experienced, to misinterpret what something meant or how to declare a more complex type.

I can't think of any example right now but more than once I've answered questions about type declarations and constness where the problem was caused by the habit of using "const T &" instead of "T const &". I used to write it that way as well and when I became a Sr. Developer, someone in charge of mentoring and creating code standards in projects, I found it much easier for entry level developers when I force everyone to use "T const&". I suppose one rather trivial, rookie mistake would be why does this code compile?


const T* t = f();
t = 0; // assignment to const?? - no, it is not the T* that is const, just the T.

When you learn to read it the way that the compiler does it becomes much easier to understand what any given complex type is as well as allowing you to more readily declare complex types when you need to. By complex types I'm talking about things such as:

T const * const &

When you know that the compiler reads right to left, inside to out, what that means becomes quite apparent and when it is necessary to write one you can do so easily: reference to constant pointer to a constant T. Now write the declaration of a "reference to a pointer to a constant pointer to a T". If you simply use left to right notation I think you'll find this quite easy.

In short, though it initially seems unnatural teaching oneself to use right->left grammar ALL the time, instead of only when it is required (because it often is), you'll find it much easier to remember what a line of code means and how to write what you mean. It's sort of along the same lines of why I disallow "," in declarations:


T* ptr1 = 0, ptr2 = 0; // oops!!!

// do it this way please! T* ptr1 = 0; T* ptr2 = 0;

Technically it's all the same but when you try to get a bunch of people of varying capacities working on the same thing you'll tend to make sure everyone uses whatever method is the easiest to understand and use. My experience has taught me that "T const&" is that method.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
4

I think is personal preference. There is no difference between the two variants.

Cătălin Pitiș
  • 14,123
  • 2
  • 39
  • 62
3

Being as code is predominantly English-based, programmers tend to read left to right, so const T& reads naturally to us where the compiler reads it inside out right to left so T const& reads naturally(reference to a const T)

Corey
  • 3,125
  • 1
  • 18
  • 14
  • 5
    Humans don't tend to read left to right - the preference is purely cultural. A sizable portion of the population read their native languages vertically (i.e. Chinese and Japanese) or right to left (i.e. Arabic and Hebrew). Have you ever bought a Japanese comic book and noticed that the pages are in "backwards" order (i.e. the spine is on the right and not the left) ? – Adisak Apr 14 '10 at 19:58
  • 1
    @Adisak: I think he meant tend as in "people who write code tend", most code writers read left-to-right since it's predominately English-based. – GManNickG Apr 14 '10 at 20:24
  • 2
    @Adisak Yes, you are right, but "const" is not a Chinese or Japanese word, it's a shortening of the English word "constant" Neither are the keywords "if", "while", "static", etc. The C++ language is tied to an English heritage. If a language exists where all the keywords are primarily Chinese characters, it would make sense to talk about its natural "right to left" reading. But then someone would argue that interpretation was primarily cultural, and humans don't tend to read right to left. Perhaps humans are flexible enough to tend to read in the direction of the language, not vice versa. – Edwin Buck Apr 14 '10 at 20:33
  • @GMan, but there are lots of coders in Israel, and the Technion is quite famous. I think Bruce meant to write "English speakers", and his point is otherwise valid. Adisak's criticism is likewise valid. – Michael Aaron Safyan Apr 14 '10 at 20:36
  • @GMAN: Yes pretty much all code is left to right. But that again is cultural conditioning (as you state, code is predominantly English-based), not human tendancy. Let's say in an alternate past, the Arab world had remained a center of knowledge and invented computers -- There is no reason that if history were different we wouldn't be reading right-to-left and writing code right-to-left. My correction is that it's not a generic "Human" tendency, but rather a cultural one (and programming is a culture as well). – Adisak Apr 15 '10 at 02:31
  • 3
    @Adisak: I see your point, and admit I worded it wrong. That was not my intent. Fixed my answer for you :) – Corey Apr 15 '10 at 04:11
1

That's because some find it helpful to read the declaration right-to-left.

char const*
const char*

are both pointer to const char.

JRL
  • 76,767
  • 18
  • 98
  • 146
1

I used to be a strong advocate of const T& because it does read logically left-to-right (it's a constant T reference). (And probably there's some bias since most code I'd encountered to that point was written that way.)

Over the years I've encountered some corner cases (such as multiple pointer/reference layers, multiple variable declarations, and method pointers) which strain things a little for the reasons other people have already answered. Often introducing additional typedefs help you "unstick" these cases to some extent, but then you have to come up with a name for something even if it's only used once.

The tipping point for me was the introduction of auto in C++11, especially when combined with range-based-for. With that, I've flipped and now strongly prefer T const& (or "reference to constant T", reading right to left) instead. Not only is it more consistent with how the compiler actually parses, it means that when you replace the type with auto, this always ends up at the left, which I think reads better.

Compare:

for (const T& a : list)         for (T& a : list)
for (T const& a : list)         for (T& a : list)
for (const auto& a : list)      for (auto& a : list)
for (auto const& a : list)      for (auto& a : list)

Note also the column on the right, where I've added the non-const version of the same. At least for me, the const vs. non-const and auto vs. explicit all seem most consistent in the cases where const appears after T.

But this is a style choice, and as such there is no absolutely correct answer.

Miral
  • 12,637
  • 4
  • 53
  • 93
1

If the const and & get far apart, as in

krog::FlamBlott<std::map<HurkleKey,Spleen<int>>
speckleFlams( const krog::Floonage & floon, const std::map<krog::HackleSpoon,std::vector<krog::HeckleObservation<OBSN>>> & obsmap);

krog::FlamFinagleReport
finagleFlams( const krog::Floonage & floon, std::map<krog::HackleSpoon,std::vector<krog::HeckleObservation<OBSN>>> & obsmap)

... then it becomes easy to miss that the first 'obsmap' is a const reference and the second is not.

greggo
  • 3,009
  • 2
  • 23
  • 22
1

I use the T const& notation myself, and I recommend it to everyone. The reason is the ergonomics - i find it to reduce eye movement.

@grego already made a great point on how "const" being close to "&" prevents bugs. Usualy when I find "&" I want to know if it is const or not, and moving my eyes left-and-right is not what I want to do all the time.

There is another reason for <T const&> not mentioned before - code alignment. Let's see which declaration is easier to read:

void append(std::string& str,
            const std::vector<std::string>& elements,
            const char* delimiter);

void append(std::string& str,
            std::vector<std::string> const& elements,
            char const* delimiter);

<const T&> hides the type in the middle, while <T const&> exposes it on the left side. <T const&> aligns the type to the same column sliding from top to bottom can be with much less left-right eye movement when looking for a specific argument's type.

For the same reason I like the trailing return type notation (auto f(...) -> R)

Bartosz Charuza
  • 491
  • 1
  • 7