我有以下代码:
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++
更有帮助。除了指出 noexcept
的参数必须是常量表达式的错误消息外,它还显示:
note: undefined function 'foo' cannot be used in a constant expression
note: declared here
static constexpr bool foo() { return true; }
^
那么...这是一个两遍编译问题吗?编译器是否试图在定义类中的所有成员函数之前声明它们的问题? (请注意,在类的上下文之外,编译器都不会抛出错误。)这让我感到惊讶;直观地说,我看不出有任何理由让 static constexpr
成员函数不能在类内或类外的任何和所有常量表达式中使用。
最佳答案
作为 T.C.通过评论中的一些链接进行演示,标准对此并不相当明确;使用 decltype(memberfunction())
的尾随返回类型也会出现类似的问题。
核心问题是,在声明它们的类完成之前,通常不会考虑声明类成员。因此,不管 foo
是 static constexpr
并且它的声明先于 bar
的事实,在 MyClass
完成之前,它不能被认为是“可用的”用于常量表达式。
作为 pointed out by 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,因为这里仍然只有 一个 正确的程序是可能的。)
这种行为实际上可能是违反标准的; T.C.指出(在下面的评论中)这里的 foo
实际上应该在整个类(class)的范围内查找。当首先声明 bar
时,g++ 4.9.2 和 clang++ 3.5.1 都失败并出现错误,但在首先声明 foo
时编译时没有错误或警告。 编辑:当首先声明 bar
时,clang++ trunk-revision 238946(来自 3.7.0 发布前不久)不会失败; 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
的 声明 的 bar2
规范计算为 noexcept(false)
,然后将其视为与 noexcept(noexcept(MyClasss::foo2()))
不匹配。
关于c++ - `static constexpr` 在常量表达式中调用的函数是...错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29551223/