Почему некоторые люди предпочитают "T const &" вместо "const T &"? - PullRequest
55 голосов
/ 14 апреля 2010

Итак, я понимаю, что const T& и T const& идентичны и оба означают ссылку на const T. В обоих случаях ссылка также постоянна (ссылки не могут быть переназначены, в отличие от указателей).Из своего ограниченного опыта я заметил, что большинство программистов на C ++ используют const T&, но я встречал несколько человек, которые используют T const&.Я использую const T& просто потому, что я научился этому, и поэтому T const& выглядит немного смешно для меня.По какой причине вы используете тот вариант, который используете?Кто-нибудь из вас работает в организации, для которой стандарты кодирования требуют использования одного варианта над другим?

Редактировать Исходя из ответов, может показаться, что одной из причин выбора между этими двумя является то, хотите ли вы читать его как компилятор (справа налево) или как английский (слева направо).Если читать его как компилятор, то «T const &» читается как «& (ссылка) const (на константу) T (типа T)».Если читать слева на право, как на английском, то «const T &» читается как «постоянный объект типа T в виде ссылки».Я предпочитаю читать это как английскую прозу, но я определенно вижу смысл интерпретировать это так, как это делает компилятор.

Никто не ответил на вопрос об организации или стандартах кодирования, но я сильно подозреваю, что большинство организацийне поручайте одно другому, хотя они могут стремиться к последовательности.

Ответы [ 9 ]

43 голосов
/ 14 апреля 2010

Я думаю, что некоторые люди просто предпочитают читать декларации справа налево. const применяется к левому токену, кроме случаев, когда там ничего нет, и он применяется к правому токену. Следовательно, const T& включает в себя фразу «кроме» и, возможно, может считаться более сложной (в действительности оба должны быть настолько просты для понимания).

Сравнить:

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)
26 голосов
/ 15 апреля 2010

Это будет иметь значение, когда у вас будет более одного модификатора const / volatile. Тогда его размещение слева от типа все еще допустимо, но нарушит последовательность всей декларации. Например:

T const * const *p;

означает, что p является указателем на const-указатель на const T, и вы последовательно читаете справа налево.

const T * const *p;

означает то же самое, но консистенция потеряна, и вы должны помнить, что крайняя левая константа / volatile связана только с T, а не с T *.

7 голосов
/ 28 мая 2010

Если вы находите это обсуждение интересным, вы, вероятно, найдете эту статью Дэна Сакса интересной. Он не имеет прямого отношения к вашему вопросу, но объясняет, почему он предпочитает

VP const foo[];

до

const VP foo[];

Это потому что дано

typedef void *VP;

Вы легко можете быть введены в заблуждение, думая, что второй пример выше означает

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

но первый пример труднее неверно истолковать.

3 голосов
/ 15 апреля 2010

Мои рассуждения таковы:

Кажется, что лучше скатиться с языка, если вы напишите «const T &», но когда вы сделаете это, вы получите неоднозначную «константную T-ссылку». Я неоднократно сталкивался с этой проблемой в понимании кода, который позволял кому-то, даже немного опытному, неправильно истолковывать, что что-то значит или как объявлять более сложный тип.

Я не могу вспомнить ни одного примера прямо сейчас, но я не раз отвечал на вопросы об объявлениях типов и константности, где проблема была вызвана привычкой использовать «const T &» вместо «T const &». Я тоже так писал, и когда я стал старшим разработчиком, ответственным за наставничество и создание стандартов кода в проектах, я обнаружил, что для разработчиков начального уровня намного проще, когда я заставляю всех использовать «T const &». Полагаю, одна довольно тривиальная ошибка новичка - почему этот код компилируется?

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

Когда вы научитесь читать его так, как это делает компилятор, становится намного легче понять, что представляет собой любой данный сложный тип, а также позволяет вам более легко объявлять сложные типы, когда вам это необходимо. Под сложными типами я говорю о таких вещах, как:

T const * const &

Когда вы знаете, что компилятор читает справа налево, изнутри наружу, то, что это означает, становится вполне очевидным, и когда необходимо написать его, вы можете сделать это легко: ссылка на постоянный указатель на постоянную T. Теперь запишите объявление «ссылки на указатель на постоянный указатель на T». Если вы просто используете обозначение слева направо, я думаю, вы найдете это довольно просто.

Короче говоря, хотя поначалу кажется неестественным учить себя использовать правую> левую грамматику ВСЕ время, а не только тогда, когда это требуется (потому что это часто так), вам будет гораздо проще запомнить, что такое строка кода означает и как написать то, что вы имеете в виду. Это похоже на то, почему я запрещаю "," в объявлениях:

<code>
T* ptr1 = 0, ptr2 = 0; // oops!!!</p>

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

Технически это все одно и то же, но когда вы пытаетесь заставить группу людей разной квалификации работать над одной и той же вещью, вы будете стремиться к тому, чтобы каждый использовал любой метод, который проще всего понять и использовать. Мой опыт научил меня, что "T const &" - ​​это тот метод.

3 голосов
/ 14 апреля 2010

Поскольку код основан преимущественно на английском языке, программисты обычно читают слева направо, поэтому const T& естественно читает нам, когда компилятор читает его наизнанку справа налево, поэтому T const& читает естественно (ссылка на const T )

3 голосов
/ 14 апреля 2010

Я думаю, это личное предпочтение. Между этими двумя вариантами нет никакой разницы.

1 голос
/ 19 июля 2018

Раньше я был сильным сторонником const T&, потому что он читает логически слева направо (это константа T ссылка). (И, вероятно, есть некоторая предвзятость, поскольку большая часть кода, с которым я столкнулся на тот момент, была написана именно так.)

За прошедшие годы я столкнулся с некоторыми угловыми случаями (такими как множественные указатели / ссылочные слои, множественные объявления переменных и указатели методов), которые немного напрягают по причинам, на которые другие люди уже ответили. Часто введение дополнительных typedefs помогает вам в некоторой степени «открепить» эти случаи, но затем вам нужно придумать имя для чего-то, даже если оно используется только один раз.

Переломным моментом для меня стало введение auto в C ++ 11, особенно в сочетании с Range-based-for. После этого я перевернул и теперь сильно предпочитаю T const& (или «ссылка на постоянную T», читая справа налево). Он не только более соответствует тому, как фактически анализирует компилятор, но и означает, что когда вы заменяете тип на auto, он всегда заканчивается слева, что, я думаю, читается лучше.

Сравните:

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)

Обратите внимание также на столбец справа, где я добавил неконстантную версию того же самого. По крайней мере, для меня, const против неконстантных и auto против явных все кажутся наиболее последовательными в случаях, когда const появляется после T.

Но это выбор стиля, и поэтому нет абсолютно правильного ответа.

1 голос
/ 14 апреля 2010

Это потому, что некоторые считают полезным читать объявление справа налево.

char const*
const char*

являются указателями на const char.

0 голосов
/ 26 апреля 2019

Если const и & далеко друг от друга, как в

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)

... тогда становится легко пропустить, что первый 'obsmap' является ссылкой на const, а второй - нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...