Почему функция, не имеющая идентификаторов аргументов в С++?
Учитывая функцию в С++ с аргументами, которые являются только типами и не имеют идентификаторов,
void foo1(int, int, int){cout << "called foo1";}
Я могу назвать это следующим:
int main()
{
foo1(10, 10, 10);
}
Почему это допустимая конструкция в С++? Является ли это просто идиосинкразией С++ или действительно ли такая декларация имеет какую-то цель? Можем ли мы фактически получить доступ к аргументам, которые были переданы каким-то образом?
(Этот вид объявления метода не будет работать на Java.)
Ответы
Ответ 1
Рассмотрим случай, когда вам необходимо предоставить функцию, которая соответствует следующему прототипу
void dostuff(int x, int y, int z);
И скажите, что вы работаете в 2D-пространстве и не используете z
внутри своей реализации. Вы можете
void dostuff(int x, int y, int z)
{
// use x and y
}
и просто игнорировать z
, но компилятор, скорее всего, обнаружит, что вы определили, но не использовали z
, и предупредите, что вы можете сделать ошибку. Вместо этого вы можете
void dostuff(int x, int y, int )
{
// use x and y
}
и оставьте определение z
. Компилятор будет принимать и молча отбрасывать третий параметр, потому что он знает, что вы этого не хотите.
Вы не хотите просто отключать предупреждение из-за ошибок, подобных этому
void dostuff(int x, int y, int z)
{
for (int z = 0; z < MAX; z++)
{
// use x and y and z, the local z.
}
}
В тех случаях, когда индексированный индекс петли теряет параметр z
. Ввод вызывающего абонента теперь игнорируется, и это может иметь плохие последствия. Эта ошибка часто бывает трудно заметить с помощью глазного яблока с отметкой 1, особенно если локальный z
похоронен где-то глубоко в сложной функции.
В любое время, когда компилятор может выбрать возможную ошибку в вашем коде, воспользуйтесь преимуществом. Это означает, что вам будет меньше работы.
Ответ 2
Объявление типа
void foo1(int, int, int){cout << "called foo1";}
ясно показывает в объявлении, что вы хотите выполнить требование с помощью вашей функции - например, переопределить определенную функцию в базовом классе или интерфейсе, который, например, может быть объявлен там как
virtual void foo1(int something, int another, int andAnother) = 0;
НО вы не собираетесь использовать параметры, которые вам переданы.
Еще один пример: если вы хотите передать функцию, например, другая функция, которая ожидает указатель на функцию void с тремя параметрами int.
void giveMeFoo( void (*fn)(int, int, int) ) { ... }
Кроме того, более высокие уровни предупреждения вызывают предупреждение, если объявлены параметры, которые не оцениваются в теле функции. Вы можете избежать этого, оставив имена параметров далеко.
Параметры без имен тогда действительно недоступны в теле функции больше - специально. user4581301 хорошо описал, почему.
Объявление автономной функции без имен параметров, как в вашем примере, разрешено из-за описанных выше способов использования, но в большинстве случаев это явно не имеет смысла. Пример, где это имеет смысл, находится в разделе комментариев. Другим примером автономной функции без имен параметров может быть, если вы пишете библиотеку и хотите либо поддерживать обратную совместимость (функция библиотеки больше не нуждается в этом параметре, но вы не хотите нарушать объявление публичного заголовка) или вы хотите зарезервировать параметр для будущего использования.
Ответ 3
Да. Это законно в С++.
С++ 11 n3337 стандарт 8.4.1 (p6) Определения функций:
Примечание. Невозможно назвать неиспользуемые параметры. Например,
void print(int a, int) {
std::printf("a = %d\n", a);
}
Стандарт С++ 14:
[8.3.5.11] В качестве имени параметра может быть указан идентификатор; если он присутствует в определении функции, он называет параметр (иногда называемый "формальный аргумент" ). [Примечание: в частности, параметр имена также являются необязательными в определениях функций и именах, используемых для параметр в разных объявлениях и определение функции не обязательно должны быть одинаковыми.]
Ответ 4
Это законно, и если вам интересно, почему:
Как правило, неназванные аргументы возникают из-за упрощения кода или от планирования вперед для расширений. В обоих случаях аргумент на месте, хотя и не используется, гарантирует, что вызывающие повлиял на изменение.
Отрывок из: Bjarne Stroustrup. "Язык программирования С++, четвертое издание".