34

我有以下代码:

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.

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

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

那么......这是一个两遍编译问题吗?编译器是否试图在定义类中的所有成员函数之前声明它们的问题?(请注意,在类的上下文之外,编译器都不会抛出错误。)这让我感到惊讶;直观地说,我看不出有任何理由让static constexpr成员函数不能在类内部或外部的任何和所有常量表达式中使用。

4

1 回答 1

19

正如 TC 在评论中的一些链接所展示的那样,标准对此并不十分清楚;使用decltype(memberfunction()).

核心问题是,类成员通常在声明它们的类完成之后才被认为是被声明的。foo因此,不管isstatic constexpr及其声明先于的事实,在完成之前bar,它都不能被视为“可用”用于常量表达式MyClass

正如Shafik Yaghmour 所指出的那样,标准中有一些尝试避免依赖于类中成员的排序,并且显然允许原始问题中的示例编译会引入排序依赖(因为foo需要声明之前bar)。然而,对排序的依赖已经constexpr很小了,因为虽然不能在内部调用noexcept函数,但noexcept表达式本身可能依赖于类内部的较早声明:

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,因为这里仍然只有一个正确的程序是可能的。)

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

有趣的是,以下变体导致使用 clang++ 而不是使用 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())) { }

根据错误,声明noexcept规范评估为,然后将其视为.bar2noexcept(false)noexcept(noexcept(MyClasss::foo2()))

于 2015-04-15T23:09:35.830 回答