Я хотел бы объявить четные значения параметров как const
где это возможно, и, ища ТАК, я обнаружил, что это не так уж редко. Как это:
int add(const int a, const int b)
{
...
}
Но мне интересно const
за ценности это деталь реализации моей функции, а не часть ее интерфейса. Поэтому вставлять его в прототип кажется ненужным.
Этот прототип для вышеуказанной функции, кажется, работает просто отлично:
int add(int a, int b);
Тем не менее я слышал о проблемах, например, Объявление argc главной функции как const может привести к проблемам:
int main(const int argc, const char* const argv[])
Значит ли это, что int add(int a, int b)
а также int add(const int a, const int b)
не идентичны в конце концов?
И если это технически нормально, это то, что я должен сделать? Я мог бы также пропустить имена переменных в прототипе, но я не могу, поэтому, возможно, я не должен пропустить const
или?
Это не хорошо для тип функции отличаться, но вы должны знать, что является частью типа функции, а что нет. В вашем случае const
для параметров не имеет значения, поэтому тип функции остается тем же, хотя декларация похоже, это отличается от определение.
В вашем случае это
8.3.5 Функции [dcl.fct]
5 Одно имя может использоваться для нескольких различных функций в одной области видимости; это перегрузка функции (пункт 13). Все объявления для функции должны точно совпадать как с типом возвращаемого значения, так и со списком параметров-типов. Тип функции определяется с использованием следующих правил. Тип каждого параметра (включая пакеты параметров функции) определяется из его собственных decl-specier-seq и декларатора. После
При определении типа каждого параметра любой параметр типа «массив из T» или «функция, возвращающая T» настраивается на «указатель на T» или «указатель на функцию, возвращающую T», соответственно. После создания списка типов параметров любые cv-квалификаторы верхнего уровня, модифицирующие тип параметра, удаляются при формировании типа функции. Результирующий список преобразованных типов параметров и наличие или отсутствие многоточия или пакета параметров функции представляет собой список параметров типа функции. [Примечание: это преобразование не
влияет на типы параметров. Например,int(*)(const int p, decltype(p)*)
а такжеint(*)(int, const int*)
одинаковые типы. — конец примечания]
Как кажется, это нуждается в некотором объяснении, поэтому здесь мы идем: Важное предложение в нашем случае: После создания списка типов параметров любые cv-квалификаторы верхнего уровня, модифицирующие тип параметра, удаляются при формировании типа функции.
Это означает, что все верхний уровень cv-квалификатор удаляется. Чтобы объяснить, что означает верхний уровень, я напишу типы недопустимым образом, чтобы подчеркнуть, что const
относится к:
const int
знак равно (const (int))
-> это на высшем уровне const
const int*
знак равно ((const (int))*)
-> не на высшем уровне, это на втором уровнеconst int* const
знак равно (((const (int))*) const)
-> второй const
находится на высшем уровнеconst int&
знак равно ((const (int))&)
-> не на высшем уровнеЯ надеюсь, что это очищает некоторые неправильные представления о типах функций.
По другим вашим вопросам: я бы посоветовал сохранить идентичность декларации и определения, так как это могло бы сбить людей с толку (как свидетельствует этот вопрос;).
Для примера main
что вы дали:
int main( const int argc, const char* const argv[] )
согласно приведенной выше цитате из стандарта эквивалентно:
int main( int argc, const char* const* argv )
так что добавил const
за argv
не заканчивается как на высшем уровне const
который удаляется, и, следовательно, это плохо сформированный тип функции для main
, который ожидает:
int main( int argc, char** argv )
Ваш последний вопрос об исключении имен параметров: я бы не стал этого делать, потому что для меня они являются частью документация функции. Они сообщают о намерениях и семантике функции (если вы выбираете их с умом).
Должно быть в порядке, чтобы иметь различный верхний уровень const
для параметров функции между объявлениями и определениями функции, но обратите внимание, что не все компиляторы не содержат ошибок. Например, компилятор Oracle Sun имеет давняя проблема где это калечат int f(int)
а также int f(const int)
по-другому.
Чтобы избежать путаницы, которую вы действительно хотели пройти мимо const
ссылка, которую я обычно рекомендую избегать верхнего уровня const
в публичных объявлениях функций и во избежание возможных проблем с компилятором я бы избегал этого и в определениях функций.
(Обратите внимание, что изменение char **
в const char* const argv[]
в список аргументов не добавляется const верхнего уровня, это подлинное изменение подписи. char**
будет только эквивалентно char** const
в списке параметров функции.)
const для значений — это деталь реализации моей функции, а не часть ее интерфейса.
Это недостаток вашего мышления, когда речь идет о ссылках и указателях const
имеет все, что связано с интерфейсом, он говорит программисту, используя интерфейс, что то, что вы передаете, не будет изменено функцией. Это говорит компилятору то же самое и связывает программиста с этим контрактом.
Функция с const
аргумент и один с неconst
аргумент разные.
Передача по значению, однако, скопирует аргументы, и в этом случае изменение их не является проблемой. Ваш int
s передаются по значению, где это const
не будет иметь большого значения.
Однако лично я не думаю, что это является причиной злоупотребления наличием несовместимых интерфейсов, и делает интерфейсы разными в одном месте и в другом.
В то время как проходя мимо ref, ссылка на const
довольно сильно отличается отconst
,