Взаимодействие "if constexpr" с предупреждением "try in constexpr function"

Я утверждаю, что эта программа должна быть правильно сформирована: она объявляет функцию-член constexpr S<int>, Однако и GCC, и Clang отклоняют эту программу.

template<class T>
struct S {
    constexpr int foo() {
        if constexpr (std::is_same_v<T, int>) {
            return 0;
        } else {
            try {} catch (...) {}
            return 1;
        }
    }
};

int main()
{
    S<int> s;
    return s.foo();  // expect "return 0"
}

GCC говорит:

ошибка: попробуйте в функции constexpr

Clang говорит:

ошибка: оператор не разрешен в функции constexpr

Ни один из них, кажется, не замечает, что оператор "try" находится в отброшенной ветви if constexpr заявление.

Если я фактор try / catch в функцию - член non-constexpr void trycatch() затем и Clang, и GCC снова довольны кодом, хотя его поведение должно быть эквивалентно несчастной версии.

template<class T>
struct S {
    void trycatch() {
        try {} catch (...) {}
    }
    constexpr int foo() {
        if constexpr (std::is_same_v<T, int>) {
            return 0;
        } else {
            trycatch();  // This is fine.
            return 1;
        }
    }
};

Это

  • ошибка как в GCC, так и в Clang?
  • дефект в стандарте, который GCC и Clang добросовестно внедряют?
  • проблема качества реализации из-за "условного соответствия" foo()?

(Неактуальный фон: я внедряю constexpr any::emplace<T>() для версии с поддержкой распределителя any чей распределитель может быть constexpr-per- P0639 (то есть может отсутствовать deallocate функция-член) или не может. В первом случае мы не хотим или не нуждаемся в try; в последнем случае нам нужно try для того, чтобы позвонить deallocate если конструктор T броски.)

1 ответ

Компиляторы подчиняются Стандарту. В проекте C++17 N4659 говорится ([dcl.constexpr]/(3.4.4)):

Определение функции constexpr должно удовлетворять следующим требованиям:

  • ...

  • его функция-тело должно быть = delete, = defaultили составной оператор, который не содержит

    • ...

    • пробный блок, или

    • ...

И ни одно из правил для "исключенных заявлений", таких как else утверждение в вашем S<int>::foo переопределить это правило. Единственные особые вещи, которые указаны в отношении отброшенных операторов, - это то, что отброшенные операторы не создаются, а использование odr в опущенных операторах не требует определения используемого объявления и отбрасывается return операторы игнорируются при определении истинного типа возврата функции с типом возврата заполнителя.

Я не видел ни одной существующей проблемы C++, обсуждающей это, и документ P0292R1, в котором предлагалось if constexpr не касается взаимодействия с функциями constexpr.

Другие вопросы по тегам