ПроблемаЭтот дефект возникает, когда из описания не ясно, предназначено ли объявление объекта или описание функции/параметра. Неоднозначность часто называют наиболее странным разбором.
Например, эти объявления неоднозначны:
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();
Объявление объекта:
Если объявление ссылается на объект, инициализированный конструктором по умолчанию, перезаписайте его следующим образом:
до 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);