Ambiguous declaration syntax

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

Описание

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

Для образца эти заявления неоднозначны:

  • ResourceType aResource();

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

  • TimeKeeper aTimeKeeper(Timer());

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

Проверка не помечает неоднозначные объявления с глобальными возможностями. Например, анализ не помечает объявления с глобальными возможностями, используя формат Type a() где Type является типом класса с конструктором по умолчанию. Анализ интерпретирует a как функция, возвращающая тип Type.

Риск

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

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

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

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

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

Зафиксировать

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

  • ResourceType aResource();

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

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

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

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

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

    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