在常量表达式中调用的 `static constexpr` 函数是……一个错误?

`static constexpr` function called in a constant expression is...an error?

我有以下代码:

class MyClass
{
  static constexpr bool foo() { return true; }
  void bar() noexcept(foo()) { }    
};

我希望由于 foo() 是一个 static constexpr 函数,并且由于它是在声明 bar 之前定义的,所以这是完全可以接受的。

但是,g++ 给我以下错误:

 error: ‘static constexpr bool MyClass::foo()’ called in a constant expression

这...没什么帮助,因为在常量表达式中调用函数的能力是 constexpr.[=21= 的全部要点]

clang++ 更有帮助。除了指出 noexcept 的参数必须是常量表达式的错误消息外,它还表示:

note: undefined function 'foo' cannot be used in a constant expression
note: declared here
static constexpr bool foo() { return true; }
                      ^

所以...这是一个二次编译问题吗?问题是编译器在定义 class 之前试图声明所有成员函数吗? (请注意,在 class 的上下文之外,编译器都不会抛出错误。)这让我感到惊讶;直觉上,我看不出任何 static constexpr 成员函数不能用于 class 内部或外部的任何和所有常量表达式的原因。

为T.C。在评论中用一些链接进行了演示,标准对此 相当 不清楚;使用 decltype(memberfunction()).

的尾随 return 类型会出现类似的问题

主要问题是 class 成员通常在声明它们的 class 完成后才被视为已声明。因此,不管 foostatic constexpr 并且它的声明先于 bar,它不能被认为是 "available" 用于常量表达式,直到 MyClass完成。

作为 pointed out by Shafik Yaghmour,标准中有一些尝试避免依赖 class 中成员的顺序,显然允许编译原始问题中的示例会引入一个顺序依赖(因为 foo 需要在 bar 之前声明)。但是,已经对顺序有轻微的依赖性,因为虽然 constexpr 函数不能在 noexcept 中被 调用 , noexcept 表达式 本身 可能依赖于 class:

中的早期声明
class MyClass
{
    // void bar() noexcept(noexcept(foo())); // ERROR if declared here
    static constexpr bool foo();
    void bar() noexcept(noexcept(foo())); // NO ERROR
}

(请注意,这实际上并不违反 3.3.7,因为这里仍然只有 一个 正确的程序是可能的。)

这种行为实际上可能是违反标准的; T.C。指出(在下面的评论中)这里的 foo 实际上应该在整个 class 的范围内查找。当首先声明 bar 时,g++ 4.9.2 和 clang++ 3.5.1 都失败并出现错误,但当首先声明 foo 时,编译时没有错误或警告。 编辑: clang++ trunk-revision 238946(从 3.7.0 发布前不久开始)在首先声明 barnot 失败; g++ 5.1 仍然失败。

有趣的是,以下变体导致 "different exception specifier" with clang++ 但 not with g++:

class MyClass
{
  static constexpr bool foo2();
  void bar2() noexcept(noexcept(foo2()));
};

constexpr bool MyClass::foo2() { return true; }
void MyClass::bar2() noexcept(noexcept(MyClass::foo2())) { }

根据错误,bar2 声明 noexcept 规范评估为 noexcept(false),然后被认为是不匹配noexcept(noexcept(MyClasss::foo2())).