Подтвердить что ты не робот

Почему код С++ без формального имени аргумента в определении функции компилируется без предупреждений?

При запуске с некоторым кодом MFC, созданным VS2005, я заметил, что он переопределяет метод с чем-то вроде этого:

void OnDraw(CDC* /*pDC*/)
{
    ...
    // TODO: Add your code here
}

Итак, как только я добавил что-то, я понял, что мне нужно отменить комментарий формального аргумента pDC для компиляции, но я смущен относительно того, как/почему функция С++ может компилироваться (без предупреждений) когда формальный аргумент имеет только тип, а не имя:

void foo(int)
{
    int x = 3;
}
int main()
{
    foo(5);
    return 0;
}

Не должно ли это генерировать хотя бы предупреждение (с -Wall или /W 4)? Кажется, это не так. Я что-то упускаю? Есть ли случай, когда это полезно или просто потому, что компилятор не может определить разницу между объявлением функции (только требуемые типы) и определением (полностью указанным) до тех пор, пока строка не будет обработана?

4b9b3361

Ответ 1

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

Что касается того, почему нет предупреждения - я думаю, это потому, что это проблема, это субъективная вещь, а другие люди (особенно разработчики компилятора) не считают ее проблемой. Как только вы на самом деле собираетесь использовать этот параметр, вы получите компилятор, чтобы жаловаться, если вы забудете раскомментировать имя, чтобы вы могли жаловаться только тогда, когда вам это действительно нужно (версия компилятора гибкого YAGNI: "You Arent Gonna Neet It".

Противоположная ситуация, как правило, возникает, когда вы запускаете предупреждения - именованные параметры, которые не используются, генерируют предупреждения - опять же, вероятно, почему сгенерированная функция имеет имя, прокомментированное.

Ответ 2

Самая распространенная причина, по которой я видел, - подавить неиспользуемые предупреждения переменных, которые компилятор будет использовать для:

#include <iostream>

void foo(int source)
{
  std::cout << "foo()" << std::endl;
}

int main()
{
  foo(5);
  return 0;
}

gcc говорит: main.cc:3: warning: unused parameter 'source'

Существует два распространенных способа избавиться от предупреждения: прокомментировать имя переменной или полностью удалить ее:

void foo(int /*source*/)
{
  std::cout << "foo()" << std::endl;
}

против

void foo(int)
{
  std::cout << "foo()" << std::endl;
}

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

Qt (и, возможно, другие фреймворки) предоставляет макрос, который подавляет предупреждение без необходимости комментировать или удалять имя переменной: Q_UNUSED(<variable>):

void foo(int source)
{
  Q_UNUSED(source); // Removed in version 4.2 due to locusts
  std::cout << "foo()" << std::endl;
}

Это позволяет вам вызывать в теле функции, что переменная не используется, и дает отличное место для документа , почему он не используется.

Ответ 3

С++ 11 Стандартная черновая версия N3337

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf говорит, что это законно в 8.4.1/6   "Определения функций > В общем":

Примечание. Невозможно назвать неиспользуемые параметры. Например,

void print(int a, int) {
    std::printf("a = %d\n",a);
}

Более точно, 8.4.1/1 говорит, что грамматика для определения функций

function-definition:
    attribute-specifier-seqopt decl-specifier-seqopt
    declarator virt-specifier-seqopt function-body

Затем, если вы следуете определениям грамматики, например. в разделе "Резюме грамматики приложения А" вы увидите, что имена являются необязательными.

Ответ 4

Он компилируется, потому что языковой стандарт специально говорит, что он должен компилироваться. Другого ответа нет. Это один из битов, которые делают С++ отличным от C. В именах параметров C в определении функции должно присутствовать, в С++ они являются необязательными.

Я действительно задаюсь вопросом, почему вы задаете свой вопрос "почему". Вы видите что-то неестественное, необычное или нелогичное в этом поведении?