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说:
error: ‘try’ in ‘constexpr’ function
Clang说:
error: statement not allowed in constexpr function
他们似乎都没有注意到“try”语句位于if constexpr语句的废弃分支中.
如果我将try / catch输出到非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()的“conditional constexprness”引起的实施质量问题?
(不相关的背景:我正在为任何分配器感知版本的任何:: emplace< T>()实现constexpr,其分配器可能是constexpr-per-P0639(即它可能缺少deallocate成员函数)或者可能没有.前一种情况我们不想要或不需要尝试;在后一种情况下我们需要尝试以便在T的构造函数抛出时调用deallocate.)
解决方法
The definition of a constexpr function shall satisfy the following requirements:
…
its function-body shall be
= delete
,= default
,or a compound-statement that does not contain
…
a try-block,or
…
并且“废弃语句”的规则(例如S< int> :: foo中的else语句)都没有覆盖此规则.关于废弃语句的唯一特殊事项是废弃语句没有实例化,废弃语句中的odr-uses不会导致需要使用声明的定义,并且在确定函数的真实返回类型时忽略丢弃的return语句使用占位符返回类型.
我没有看到任何现有的C问题讨论这个,以及文件P0292R1,它提出了constexpr是否不解决与constexpr函数的交互.