Так, я понимаю это const T&
и T const&
идентичны, и оба имеют в виду ссылку на константу T. В обоих случаях ссылка является также постоянной (ссылки не могут быть повторно присвоены, в отличие от указателей). Я заметил в моем несколько ограниченном опыте, что большинство программистов на C++ использует const T&
, но я столкнулся с несколькими людьми, которые используют T const&
. Я использую const T&
просто, потому что я изучил это тот путь, и таким образом, T const&
выглядит немного забавным мне. Какова причина, что Вы используете вариант, который Вы используете? Какой-либо из Вас работает в организации, для которой стандарты кодирования передают под мандат использование одного варианта по другому?
Править
На основе ответов казалось бы, что одна причина выбора между этими двумя состоит в том, хотите ли Вы считать его как компилятор (справа налево) или как английский язык (слева направо). Если Вы читаете его как компилятор, то "T const&" чтения как "и (ссылочная) константа (к константе) T (типа T)". Если Вы читаете его как английский язык, слева направо, то "константа T&" читается как "постоянный объект типа T в форме ссылки". Я предпочитаю читать его как английская проза, но я могу, конечно, видеть смысл в интерпретации его способ, которым делает компилятор.
Никто не ответил на организацию или вопрос о стандартах кодирования, но я сильно подозреваю, что большинство организаций не передает под мандат один по другому, хотя они могли бы бороться за непротиворечивость.
Я думаю, что некоторые люди просто предпочитают читать объявления справа налево. 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)
Я рассуждаю следующим образом:
Кажется, что язык лучше скатывается, если вы напишете «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». Если вы просто используете нотацию слева направо, я думаю, вы найдете это довольно легко.
Короче говоря, хотя поначалу кажется неестественным учить себя использовать правую-> левую грамматику ВСЕГДА, а не только тогда, когда это необходимо (потому что это часто бывает), вам будет намного легче запомнить, что это за строка кода значит и как написать то, что вы имеете в виду. Это примерно то же самое, почему я запрещаю "," в объявлениях:
T* ptr1 = 0, ptr2 = 0; // oops!!!
// do it this way please!
T* ptr1 = 0;
T* ptr2 = 0;
Технически это одно и то же, но когда вы пытаетесь заставить группу людей с разным уровнем подготовки работать над одним и тем же, вы, как правило, убедитесь, что каждый использует любой метод, который легче всего понять и использовать. Мой опыт научил меня, что таким методом является «T const &».
Поскольку код преимущественно англоязычный, программисты склонны читать слева направо, поэтому const T&
читается естественно для нас, а компилятор читает его наизнанку справа налево, поэтому T const&
читается естественно (ссылка на const T)
Это будет иметь значение, если у вас более одного модификатора const / volatile. Затем размещение его слева от типа все еще действует, но нарушит целостность всего объявления. Например:
T const * const *p;
означает, что p является указателем на const указатель на const T, и вы последовательно читаете справа налево.
const T * const *p;
означает то же самое, но согласованность теряется, и вы должны помнить, что крайняя левая const / volatile привязана только к T, а не к T *.
Это потому, что некоторым полезно читать декларацию справа налево.
char const*
const char*
оба являются указателями на const char.
Я думаю, это личное предпочтение. Между двумя вариантами нет никакой разницы.
Если вам интересно это обсуждение, вы бы эта статья Дэна Сакса, вероятно, покажется интересной. Он не отвечает напрямую на ваш вопрос, но объясняет, почему он предпочитает
VP const foo[];
вместо
const VP foo[];
. Это потому, что, учитывая
typedef void *VP;
, вы можете легко ввести в заблуждение, думая, что второй пример выше означает
const void *foo[]; // Wrong, actually: void *const foo[];
, но первый пример сложнее неверно истолковать.