Можно ли использовать прототипы функций и сигнатуры реализации функций const непоследовательно?

Я хотел бы объявить четные значения параметров как 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 или?

8

Решение

Это не хорошо для тип функции отличаться, но вы должны знать, что является частью типа функции, а что нет. В вашем случае 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 )

Ваш последний вопрос об исключении имен параметров: я бы не стал этого делать, потому что для меня они являются частью документация функции. Они сообщают о намерениях и семантике функции (если вы выбираете их с умом).

10

Другие решения

Должно быть в порядке, чтобы иметь различный верхний уровень const для параметров функции между объявлениями и определениями функции, но обратите внимание, что не все компиляторы не содержат ошибок. Например, компилятор Oracle Sun имеет давняя проблема где это калечат int f(int) а также int f(const int) по-другому.

Чтобы избежать путаницы, которую вы действительно хотели пройти мимо const ссылка, которую я обычно рекомендую избегать верхнего уровня const в публичных объявлениях функций и во избежание возможных проблем с компилятором я бы избегал этого и в определениях функций.

(Обратите внимание, что изменение char ** в const char* const argv[] в список аргументов не добавляется const верхнего уровня, это подлинное изменение подписи. char** будет только эквивалентно char** const в списке параметров функции.)

1

const для значений — это деталь реализации моей функции, а не часть ее интерфейса.

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

Функция с const аргумент и один с неconst аргумент разные.

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

Однако лично я не думаю, что это является причиной злоупотребления наличием несовместимых интерфейсов, и делает интерфейсы разными в одном месте и в другом.

В то время как проходя мимо ref, ссылка на const довольно сильно отличается отconst,

0
По вопросам рекламы [email protected]