7

我声称这个程序应该是格式良好的:它声明了一个 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"
}

海湾合作委员会 说:

错误:“constexpr”函数中的“try”

铿锵声 说:

错误:constexpr 函数中不允许的语句

他们似乎都没有注意到“try”语句位于语句的废弃分支中if constexpr

如果我将try/ catchout 分解为非 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;
        }
    }
};

这是

(不相关的背景:我正在any::emplace<T>()为一个分配器感知版本实现 constexpr,any其分配器可能是 constexpr-per- P0639(即它可能缺少deallocate成员函数)或可能不是。在前一种情况下,我们不想要或不需要try; 在后一种情况下,如果throws的构造函数我们需要try调用。)deallocateT

4

1 回答 1

11

编译器遵守标准。C++17 草案 N4659 说 ([dcl.constexpr]/(3.4.4)):

constexpr 函数的定义应满足以下要求:

  • ...

  • 函数体应为,= delete= default不包含

    • ...

    • 一个try-block,或

    • ...

并且没有任何“废弃语句”规则(例如else您的语句)S<int>::foo覆盖此规则。关于废弃语句的唯一特殊规定是废弃语句没有实例化,废弃语句中的 odr-uses 不会导致需要使用声明的定义,并且return在确定函数的真实返回类型时忽略废弃语句占位符返回类型。

我没有看到任何现有的 C++ 问题讨论这个问题,并且提出的论文 P0292R1if constexpr没有解决与 constexpr 函数的交互。

于 2017-10-17T00:40:54.433 回答