clang жалуется на функцию constexpr в случае оператора switch - PullRequest
11 голосов
/ 26 марта 2019
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 & 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 и также были в порядке

Обновление:

открыл ошибка

Ответы [ 2 ]

12 голосов
/ 26 марта 2019

Clang (8.0.0) содержит ошибку здесь.

Если вы пишете constexpr auto A = X::A(); и используете case A: в вашем switch выражении, вы получаете ту же ошибку компиляции(говоря, что A не является константным выражением).

Однако, если вы удалите дела, он будет скомпилирован нормально (что означает, что A является допустимым constexpr => противоречием предыдущей ошибке).

Более того, switch(x) не удается, а switch(this->x) - успешно.Поскольку x == this->x в вашем случае, это определенно ошибка.

Как упоминалось в chtz, clang (5/6), кажется, работает просто отлично.Это не аргумент, а очевидная регрессия.

Обновление: Как упоминалось в ОП, они подали отчет об ошибке .

2 голосов
/ 26 марта 2019

Похоже, что Clang не сработает, что switch(x) является переключателем перечисления X::E.

Если вы добавите явное приведение к X::E (static_cast или в стиле C иличто угодно) ваш код компилируется без вашего изменения.

Это происходит только тогда, когда ваш класс является template.

Использование switch(this->x) также работает.

Как и всегда x является членом класса, x - это просто другое имя для this->x даже в template, это должно быть ошибкой лягушки.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...