ПроблемаЭтот дефект происходит, когда не ясно из объявления, предназначаются ли объектное объявление или функция/объявление параметра. Неоднозначность часто упоминается как самый раздражающий синтаксический анализ.
Например, эти объявления неоднозначны:
ResourceType aResource();
Это не сразу понятно если aResource
функция, возвращающая переменную типа ResourceType
или объект типа ResourceType
.
TimeKeeper aTimeKeeper(Timer());
Это не сразу понятно если aTimeKeeper
объект, созданный с безымянным объектом типа Timer
или функция с указателем функции без имени вводит как параметр. Указатель функции относится к функции без аргумента, и возвратитесь, вводят Timer
.
РискВ случае неоднозначного объявления Стандарт C++ выбирает определенную интерпретацию синтаксиса. Например:
ResourceType aResource();
интерпретирован как объявление функционального aResource
.TimeKeeper aTimeKeeper(Timer());
интерпретирован как объявление функционального aTimeKeeper
параметром без имени типа указателя функции.
Если вы или другой разработчик или рецензент кода ожидаете различную интерпретацию, результаты могут быть неожиданными.
Например, позже вы можете столкнуться с ошибкой компиляции, которая затрудняет, чтобы понять. Поскольку интерпретация по умолчанию указывает на объявление функции, если вы используете функцию в качестве объекта, компиляторы могут сообщить об ошибке компиляции. Ошибка компиляции указывает, что преобразование от функции до объекта предпринимается без подходящего конструктора.
ФиксацияСделайте объявление однозначным. Например, зафиксируйте эти неоднозначные объявления можно следующим образом:
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);