Ambiguous declaration syntax

Синтаксис объявления может быть интерпретирован как объектное объявление или часть объявления функции

Описание

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

Например, эти объявления неоднозначны:

  • ResourceType aResource();

    Это не сразу понятно если aResource функция, возвращающая переменную типа ResourceType или объект типа ResourceType.

  • TimeKeeper aTimeKeeper(Timer());

    Это не сразу понятно если aTimeKeeper объект, созданный с безымянным объектом типа Timer или функция с указателем функции без имени вводит как параметр. Указатель функции относится к функции без аргумента, и возвратитесь, вводят Timer.

Риск

В случае неоднозначного объявления Стандарт C++ выбирает определенную интерпретацию синтаксиса. Например:

  • ResourceType aResource();
    интерпретирован как объявление функционального aResource.

  • TimeKeeper aTimeKeeper(Timer());
    интерпретирован как объявление функционального aTimeKeeper параметром без имени типа указателя функции.

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

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

Фиксация

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

  • ResourceType aResource();

    Объектное объявление:

    Если объявление относится к объекту, инициализированному с конструктором по умолчанию, перепишите его как:

    ResourceType aResource;
    до C++ 11, или как:
    ResourceType aResource{};
    после C++ 11.

    Объявление функции:

    Если объявление относится к функции, используйте определение типа в функции.

    typedef ResourceType(*resourceFunctionType)();
    resourceFunctionType aResource;

  • TimeKeeper aTimeKeeper(Timer());

    Объектное объявление:

    Если объявление относится к объекту aTimeKeeper инициализированный с безымянным объектом класса Timer, добавьте дополнительную пару круглой скобки:

    TimeKeeper aTimeKeeper( (Timer()) );
    до C++ 11, или фигурные скобки использования:
    TimeKeeper aTimeKeeper{Timer{}};
    после C++ 11.

    Объявление функции:

    Если объявление относится к функциональному aTimeKeeper параметром без имени типа указателя функции используйте именованный параметр вместо этого.

    typedef Timer(*timerType)();
    TimeKeeper aTimeKeeper(timerType aTimer);

Примеры

развернуть все

class ResourceType {
      int aMember;
    public:
      int getMember();
};

void getResource() {
    ResourceType aResource();
}

В этом примере, aResource может использоваться в качестве объекта, но синтаксис объявления указывает на объявление функции.

Коррекция — использование {} для объектного объявления

Одна возможная коррекция (после C++ 11) должна использовать фигурные скобки в объектном объявлении.

class ResourceType {
      int aMember;
    public:
      int getMember();
};

void getResource() {
    ResourceType aResource{};
}
class MemberType {};

class ResourceType {
      MemberType aMember;
    public:
      ResourceType(MemberType m) {aMember = m;}
      int getMember();
};

void getResource() {
    ResourceType aResource(MemberType()); 
}

В этом примере, aResource может использоваться в качестве объекта, инициализированного с безымянным объектом типа MemberType но синтаксис объявления указывает на функцию параметром без имени типа указателя функции. Указатель функции указывает на функцию без аргументов и типа MemberType.

Коррекция — использование {} для объектного объявления

Одна возможная коррекция (после C++ 11) должна использовать фигурные скобки в объектном объявлении.

class MemberType {};

class ResourceType {
      MemberType aMember;
    public:
      ResourceType(MemberType m) {aMember = m;}
      int getMember();
};

void getResource {
    ResourceType aResource{MemberType()};
}
class Integer {
       int aMember;
    public:
       Integer(int d) {aMember = d;}
       int getMember();
};

int aInt = 0;
Integer aInteger(Integer(aInt));

В этом примере, aInteger может быть объект, созданный с безымянным объектом Integer(aInt) (объект класса Integer который самостоятельно создается с помощью переменной aInt). Однако синтаксис объявления указывает на тот aInteger функция именованным параметром aInt из типа Integer (лишняя круглая скобка проигнорирована).

Коррекция — использование {} для объектного объявления

Одна возможная коррекция (после C++ 11) должна использовать {} в объектном объявлении.

class Integer {
       int aMember;
    public:
       Integer(int d) {aMember = d;}
       int getMember();
};

int aInt = 0;
Integer aInteger{Integer{aInt}};

Коррекция — удаляет лишнюю круглую скобку для именованного объявления параметра

Если aInteger функция именованным параметром aInt, удалите лишнее () вокруг aInt.

class Integer {
       int aMember;
    public:
       Integer(int d) {aMember = d;}
       int getMember();
};

Integer aInteger(Integer aInt);

Информация о результате

Группа: Хорошая практика
Язык: C++
Значение по умолчанию: 'off'
Синтаксис командной строки: MOST_VEXING_PARSE
Удар: низко

Введенный в R2019a