Предупреждение списка отсутствующих аргументов вызова функции

Я читаю "язык программирования C++ - четвертое издание", и я печатал простое упражнение, чтобы получить представление о синтаксисе C++, и я случайно наткнулся на что-то, что заставило меня поднять бровь. Короче говоря, я забыл добавить () on accept в главном:

bool accept()
{
    cout << "Do you want to proceed (y or n)?n";

    char answer = 0;
    cin >> answer;

    if (answer == 'y')
    {
        return true;
    }
    return false;

}

int main()
{
    accept;
}

это работает и компилируется и производит (в VS2015) a

C4551 - вызов функции отсутствует список аргументов

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

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

кроме того, я решил, что изменю вызов на accept в основном, в bool a = accept; cout << a; чтобы попытаться предотвратить любую оптимизацию (если это было то, что на самом деле происходило), и это не вызывало accept() код либо.

что мне интересно знать, так это:

  1. как называется accept получение скомпилированные?
  2. почему код accept вызов
  3. почему это только предупреждение, а не ошибка (Я знаю, что могу изменить конфигурацию, чтобы отобразить ее как ошибку, я больше спрашиваю, как это принято синтаксис по умолчанию, если фактический результат отличается от ожидаемого результата так "резко?"Этот вопрос может быть основан на мнении, опустите его, если вы согласны с этим.)
  4. под управлением bool a = accept; cout << a; код в main производит 1 как выход. Как это может быть, когда false является значением bool по умолчанию (по крайней мере, в C#), и нет ничего, чтобы вернуть истинное значение, так как код accept не выполняется?

2 ответов


  1. нет никакого " call to accept". См. #3.

  2. из-за #1.

  3. использование имени функции без синтаксис вызова функции (т. е.: ()) означает, что вы получаете доступ к самой функции. Вы можете, например, сохранить его в указателе функции (через распад функции на указатель):

    using my_func = bool(*)(); //Function that takes nothing and returns a bool.
    my_func var = accept; //Store a pointer to `accept`.
    

    вы могли бы тогда выпустить var();, который назвал бы accept.

    однако, поскольку вы никогда не сохраняете функцию, компилятор догадывается, что вы, вероятно, намеревались вызов функция, не для доступа к указателю функции. accept; однако является юридическим оператором C++, поэтому компилятор не может ошибиться на нем. Он может выдавать предупреждение, так как оператор ничего не выполняет, и вы, вероятно, намеревались вызвать функцию. Это ничем не отличается от утверждения типа 1;: совершенно законно, но совершенно бесполезный.

  4. он делает это из-за обмана C++. Непустые указатели распада булевский true. И accept распадается на указатель на функцию, который не является null. Поэтому при преобразовании в bool, будет true. Ты все еще не вызов функции.


в C++ любое выражение, за которым следует точка с запятой является юридическое заявление. (Почему? Потому что C позволил вам это сделать, я думаю). Это означает, что все следующие юридические заявления:

 5;
 3 + 5;
 1 % 2 == 0;

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

в вашем случае, писать

accept;

- это юридическое заявление, потому что accept является выражением, оценивающим ссылку на функцию accept. Это значит, что accept; как утверждение означает " оценить адрес accept, то откажитесь от нее."Причина, по которой здесь не вызывается функция, заключается в том, что имя функции само по себе не вызывает функцию; вам нужны круглые скобки (оператор вызова функции), чтобы фактически сделать вызов. Это полезно, например, если вы хотите передать функцию в другую функцию. Например, вы, возможно, захотите чтобы передать функцию сравнения в std::sort, например:

std::sort(range.begin(), range.end(), nameOfMyComparisonFunction)

здесь, это было бы реальной проблемой, если это звонил nameOfMyComparisonFunction, так как аргументы не могут быть известны, пока не начнется процедура сортировки.

так почему это предупреждение, а не ошибка? Ну, это совершенно законный код C++, поэтому компилятор не может назвать его ошибкой. Однако компилятор прав, чтобы отметить его как предупреждение, так как это почти наверняка означает, что вы сделали ошибку. Тем не менее, большинство компиляторы имеют некоторую настройку, которая сообщает предупреждения как ошибки, и если вы поднимаете уровень предупреждения достаточно высоко, компилятор, вероятно,б скажите :" это настолько подозрительно, что я собираюсь предположить, что вы что-то испортили."

что касается вашего последнего - почему

bool a = accept;

в конечном итоге установка a to true? в C++ любой ненулевой указатель неявно преобразуется в true, а любой нулевой указатель неявно преобразуется в false. В C++ функции неявно конвертируемые в указатели на себя, так что в данном случае accept оценивает в адрес accept функция, которая не является нулевой, поэтому она устанавливает a to true. Когда ты тогда напишешь

cout << a << endl;

значение печатается как 1, потому что bool значения печатаются как 1 и 0, а не true и false по умолчанию. Тем не менее, вы могли бы написать

cout << boolalpha << a << endl;

и вы увидите true вместо печати.

надеюсь, что это помогает!