В настоящее время у меня есть этот блок кода, который не выдает ошибку компилятора в GCC, но выдает эту ошибку компилятора в clang:
ошибка: вложенный спецификатор имени 'MyEnum::' для объявления не относится к классу, шаблону класса или частичной специализации шаблона класса.
На самом деле я не слишком уверен, почему это так. В приведенном ниже примере кода я предложил некоторые потенциальные решения, позволяющие избежать возникновения ошибки, и мой конкретный вариант использования. Вот ссылка на скомпилированный пример: https://godbolt.org/z/57aMreM3K
#include <stdexcept>
enum class MyEnum : int {
MIN = 0,
MAX = 1
};
class TestClass {
public:
explicit TestClass(const MyEnum type) {
throw std::runtime_error("Runtime Error");
}
};
int main() {
try {
TestClass(MyEnum::MIN);
} catch(...) { }
// My usecase was to use google test to make sure there's no exception on construction
// EXCEPT_NO_THROW(TestClass(MyEnum::MIN));
// Potential solutions that compile for both GCC/Clang:
// EXCEPT_NO_THROW(auto variable = TestClass(MyEnum::MIN));
// EXCEPT_NO_THROW(TestClass((MyEnum)MyEnum::MIN));
}
@Someprogrammerdude: Или используйте дополнительные круглые скобки ((TestClass(MyEnum::MIN));), чтобы избежать изменения значения, как это иногда делают фигурные скобки (но не в этом случае).





Кланг здесь прав.
В базовой грамматике C++ для вашего утверждения имеется двусмысленность.
TestClass(MyEnum::MIN);
Зная только то, что TestClass является допустимым именем типа, но не выполняя никакого поиска, кроме этого, это может быть либо:
Оператор выражения, который состоит из явного выражения приведения функционального стиля, которое преобразует результат идентификатора-выражения MyEnum::MIN в TestClass.
Объявление со спецификатором типа TestClass, без какого-либо инициализатора и с квалифицированным идентификатором-декларатором в скобках MyEnum::MIN. Обратите внимание, что в C и C++ деклараторы всегда можно заключить в круглые скобки без изменения смысла, например. int (x) = 5; — допустимое объявление переменной x типа int, инициализированной как 5.
Вам нужен первый смысл. Однако двусмысленность всегда разрешается в пользу объявления, основанного исключительно на синтаксической форме оператора и на том, являются ли составляющие допустимым именем типа. См. [stm.ambig] в стандарте (проекте) для получения точных правил.
В частности, интерпретация объявления синтаксически возможна, но семантически некорректна, поскольку вы не можете (пере)объявить перечислитель MyEnum::MIN.
Но поскольку семантика не учитывается при устранении неоднозначности, должна быть выбрана интерпретация как декларация, и программа оказывается неправильной как следствие неправильной формы декларации.
Тот факт, что GCC не диагностирует проблему, является открытой ошибкой, см. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62116.
Простой способ предотвратить возникновение неоднозначностей такого рода — использовать фигурные скобки вместо круглых скобок для явного приведения в функциональном стиле:
TestClass{MyEnum::MIN};
В зависимости от того, что вы хотите протестировать, это может оказаться не решением, поскольку может изменить смысл выражения.
Некоторые другие возможности устранения неоднозначности в качестве оператора выражения, которые не влияют на смысл вашего выражения:
(void)TestClass(MyEnum::MIN);
static_cast<void>(TestClass(MyEnum::MIN));
(TestClass(MyEnum::MIN));
void(), TestClass(MyEnum::MIN);
TestClass(MyEnum::MIN), void();
Компилятор рассматривает
TestClass(MyEnum::MIN);какTestClass MyEnum::MIN;. То есть он думает, что вы пытаетесь определить переменную с именемMyEnum::MIN, которая недопустима при перечислении. Используйте фигурные скобки{}вместо круглых, чтобы решить задачу:TestClass{MyEnum::MIN};