Почему const разрешен в объявлениях функций? - PullRequest
0 голосов
/ 21 октября 2018

В C и C ++ параметры могут быть объявлены const при определении функции:

// without const
void foo(int i)
{
    // implementation of foo()
}

// with const
// const communicates the fact that the implementation of foo() does not modify parameter i
void foo(const int i)
{
    // implementation of foo()
}

Однако, с точки зрения вызывающей стороны, обе версии идентичны (имеют одинаковую подпись).Значение аргумента, переданного foo(), копируется.foo() может изменить эту копию, а не значение, переданное вызывающей стороной.

Это все хорошо, но разрешено использовать const также при объявлении foo():

void foo(int i); // normal way to declare foo()

void foo(const int i); // unusual way to declare foo() - const here has no meaning

Почему const допускается стандартами C и C ++ при объявлении foo(), хотя это бессмысленно в контексте такого объявления?Зачем разрешать такое бессмысленное использование const?

Ответы [ 3 ]

0 голосов
/ 21 октября 2018

Во-первых, const в списке параметров не лишен смысла.Рассмотрим этот код:

void foo(int i)
{
   i++;
   std::cout << i << "\n";
}

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

Все еще не очень полезна?В Си, может быть.В C ++ это также означает, что вы не можете вызывать неконстантные методы класса типов, передаваемые по значению.Давайте предположим, что аргумент может быть объектом типа класса и является интерфейсом к некоторому объекту, который хранится вне функции.Тогда имеет смысл объявить, что ваша функция должна оставить этот объект «неизменяемым».

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

0 голосов
/ 21 октября 2018

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

В определенииconst и другие квалификаторы имеют свои обычные эффекты, например:

int foo(const int x)
{
    x = 3; // Not permitted.
}

Предполагая, что мы не хотим потерять это поведение, разрешение классификаторов в определениях и запрет их в объявлениях, которые не являются объявлениями, излишне усложнитстандарт.Кроме того, это означает, что люди, которые скопировали определение, чтобы вставить его в другое место в качестве объявления без определения, должны будут внести дополнительные изменения, и любое программное обеспечение, предназначенное для сбора внешних определений из исходного файла, для создания заголовочного файла, содержащего объявления без определения, будет иметьвыполнить дополнительный анализ и манипулирование для удаления квалификаторов (но только для квалификаторов верхнего уровня, а не для внутренних типов, таких как int * const p).

Как правило, язык C и C ++ не запрещает «бесполезные» вещинапример, добавление постоянного нуля (который может возникнуть в результате сочетания макросов препроцессора, когда какое-либо выражение оказывается равным нулю при определенных выборках параметров сборки), изолированные пустые операторы и т. д.Эти вещи не вызывают беспокойства, если они не способствуют человеческой склонности к ошибкам.Например, если добавление нуля всегда происходило в результате ошибки (так как это никогда не происходило как следствие, такое как упомянуто выше), то запрещение этого может иметь значение.Однако, если нет никакого смысла запрещать что-либо, то затрачивать усилия на запрещение чего-либо бесполезно.

0 голосов
/ 21 октября 2018

const является классификатором типа: https://en.cppreference.com/w/cpp/language/cv

Как таковые, они могут быть добавлены к типу как часть самой грамматики.Я полагаю, они не хотели по-разному указывать аргумент и переменную.(это, вероятно, делает реализацию немного проще?)

Тогда проблема в том, что они не участвуют в подписи, когда ссылаются на сам аргумент (они являются частью подписи, когда ссылаются, например,в память, на которую указывает аргумент), как вы сказали в своем вопросе.

У clang-tidy есть правило для удаления лишнего const: https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html

...