#c #c 11
#c #c 11
Вопрос:
struct X
{
enum class E
{
A,B
};
static constexpr X A()
{
return X{E::A};
}
static constexpr X B()
{
return X{E::B};
}
constexpr operator E() const
{
return a;
}
E a;
};
template <typename T>
struct Y
{
void f()
{
// without this line clang errs
// const auto amp; x = this->x;
switch(x)
{
case X::A():
case X::B():
default: return;
}
}
X x = X::A();
};
int main()
{
Y<int>{}.f();
}
Без отмеченной строки во фрагменте clang выдает следующую ошибку:
ошибка: значение case не является регистром константного выражения
X::B():
Однако я попробовал gcc, и он скомпилировался нормально. Кто-нибудь знает, gcc проявляет снисходительность или у clang есть какая-то ошибка?
Смотрите на godbolt (clang 8.0.0):https://godbolt.org/z/ETe5WQ Однако (gcc 8.3) отлично компилируется (также на godbolt) и пробовал другие версии gcc, и они также были в порядке
Обновить:
обнаружена ошибка
Комментарии:
1. @mkmostafa если вы подозреваете ошибку компилятора, не помешало бы указать версии компилятора, которые вы использовали как gcc, так и clang.
2. Он компилируется, если вы меняете switch (x) на switch(this-> x)
3. Также компилируется с clang 5 и clang 6: godbolt.org/z/KHMnoX Я предлагаю сообщить об ошибке по адресу bugs.llvm.org
Ответ №1:
У Clang (8.0.0) здесь ошибка.
Если вы пишете constexpr auto A = X::A();
и используете case A:
в своей switch
инструкции, вы получаете ту же ошибку компиляции (говорящую, что это A
не постоянное выражение).
Однако, если вы удалите регистры, он отлично компилируется (что подразумевает, что A
является допустимым constexpr
=> противоречит предыдущей ошибке).
Более того, switch(x)
сбой при switch(this->x)
успешном выполнении. Поскольку x == this->x
в вашем случае это определенно ошибка.
Как упоминал чтз, clang (5/6), похоже, работает просто отлично. Это не аргумент, а очевидная регрессия.
Обновление: Как упоминалось в OP, они отправили отчет об ошибке.
Комментарии:
1. Эта ошибка также затрагивает версии Clang с 7.0.0 по 9.0.1 и, похоже, исправлена в версии 10.0.0. По крайней мере, это то, что я получил, вставляя код из отчета об ошибке в godbolt.
Ответ №2:
Похоже, что clang не работает, switch(x)
это переключатель в перечислении X::E
.
Если вы добавляете явное приведение к X::E
( static_cast
или в стиле C или что-то еще), ваш код компилируется без ваших изменений.
Это происходит только тогда, когда ваш класс является template
.
Использование switch(this->x)
также работает.
Поскольку всякий раз, когда x
является членом класса, x
это просто другое название для this->x
даже в template
, это должно быть ошибкой clang.
Правила того, как вы можете выполнить переключение для не-перечисляемого / целочисленного типа, интересны тем, что они основаны на существовании неопределенного оператора приведения к любому перечисляемому или целочисленному типу в switch
выражении, а затем вызывают то же приведение в case
выражении.