Почему некоторые люди предпочитают "T const &" над "const T &"?

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

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

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

Ответ 1

Я думаю, что некоторые люди просто предпочитают читать декларации справа налево. 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)

Ответ 2

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

T const * const *p;

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

const T * const *p;

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

Ответ 3

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

VP const foo[];

к

const VP foo[];

Это потому, что данный

typedef void *VP;

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

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

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


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* ptr1 = 0, ptr2 = 0; // oops!!!

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

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

Ответ 7

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

char const*
const char*

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

Ответ 8

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

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

Переломным моментом для меня стало введение auto в С++ 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.

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

Ответ 9

Если 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, а второй - нет.