Почему некоторые люди предпочитают "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, а второй - нет.