[英]`static constexpr` function called in a constant expression is...an error?
I have the following code:我有以下代码:
class MyClass
{
static constexpr bool foo() { return true; }
void bar() noexcept(foo()) { }
};
I would expect that since foo()
is a static constexpr
function, and since it's defined before bar
is declared, this would be perfectly acceptable.我希望由于
foo()
是static constexpr
function,并且由于它是在声明bar
之前定义的,因此这是完全可以接受的。
However, g++
gives me the following error:但是,
g++
给了我以下错误:
error: ‘static constexpr bool MyClass::foo()’ called in a constant expression
This is...less than helpful, since the ability to call a function in a constant expression is the entire point of constexpr
.这......没有什么帮助,因为在常量表达式中调用 function 的能力是
constexpr
的全部要点。
clang++
is a little more helpful. clang++
更有帮助。 In addition to an error message stating that the argument to noexcept
must be a constant expression, it says:除了指出
noexcept
的参数必须是常量表达式的错误消息外,它还说:
note: undefined function 'foo' cannot be used in a constant expression
note: declared here
static constexpr bool foo() { return true; }
^
So...is this a two-pass-compilation problem?那么......这是一个两遍编译问题吗? Is the issue that the compiler is attempting to declare all the member functions in the class before any of them are defined?
问题是编译器试图在定义 class 之前声明所有成员函数吗? (Note that outside of the context of a class, neither compiler throws an error.) This surprises me;
(请注意,在 class 的上下文之外,两个编译器都不会抛出错误。)这让我感到惊讶。 intuitively, I don't see any reason for
static constexpr
member functions not to be useable in any and all constant expressions, inside the class or out.直观地说,我看不出
static constexpr
成员函数不能在 class 内部或外部的任何和所有常量表达式中使用的任何理由。
As TC demonstrated with some links in a comment, the standard is not quite clear on this;正如 TC 在评论中通过一些链接所展示的那样,标准对此并不十分清楚; a similar problem arises with trailing return types using
decltype(memberfunction())
.使用
decltype(memberfunction())
尾随返回类型decltype(memberfunction())
出现类似的问题。
The central problem is that class members are generally not considered to be declared until after the class in which they're declared is complete.核心问题是类成员通常在声明它们的类完成之后才被认为是声明的。 Thus, regardless of the fact that
foo
is static constexpr
and its declaration precedes that of bar
, it cannot be considered "available" for use in a constant expression until MyClass
is complete.因此,无论
foo
是static constexpr
并且它的声明在bar
之前,它都不能被视为“可用”用于常量表达式,直到MyClass
完成。
As pointed out by Shafik Yaghmour , there is some attempt within the standard to avoid a dependency on the ordering of members within a class, and obviously allowing the example in the original question to compile would introduce an ordering dependency (since foo
would need to be declared before bar
).正如Shafik Yaghmour 指出的那样,标准中有一些尝试避免依赖于类中成员的排序,并且显然允许原始问题中的示例编译会引入排序依赖(因为
foo
需要是在bar
之前声明)。 However, there is already a minor dependency on ordering, because although constexpr
functions can't be called inside noexcept
, a noexcept
expression itself might depend on an earlier declaration inside the class:然而,已经存在对排序的轻微依赖,因为虽然不能在
noexcept
内部调用constexpr
函数,但noexcept
表达式本身可能依赖于类内部的早期声明:
class MyClass
{
// void bar() noexcept(noexcept(foo())); // ERROR if declared here
static constexpr bool foo();
void bar() noexcept(noexcept(foo())); // NO ERROR
}
(Note that this is not actually a violation of 3.3.7, since there is still only one correct program that is possible here.) (请注意,这实际上并不违反 3.3.7,因为这里仍然只有一个正确的程序是可能的。)
This behavior may actually be a violation of the standard;这种行为实际上可能是违反标准的; TC points out (in a comment below) that
foo
here should actually be looked up in the scope of the whole class. TC 指出(在下面的评论中)实际上应该在整个类的范围内查找此处的
foo
。 Both g++ 4.9.2 and clang++ 3.5.1 fail with an error when bar
is declared first but compile with no errors or warnings when foo
is declared first.当首先声明
bar
时,g++ 4.9.2 和 clang++ 3.5.1 都失败并出现错误,但在首先声明foo
时编译时没有错误或警告。 EDIT: clang++ trunk-revision 238946 (from shortly before the release of 3.7.0) does not fail when bar
is declared first;编辑: clang++ trunk-revision 238946(在 3.7.0 发布前不久)在
bar
首先声明时不会失败; g++ 5.1 still fails. g++ 5.1 仍然失败。
Intriguingly, the following variation causes a "different exception specifier" with clang++ but not with g++:有趣的是,以下变体会导致使用 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())) { }
According to the error, the noexcept
specification for the declaration of bar2
evaluates to noexcept(false)
, which is then considered a mismatch for noexcept(noexcept(MyClasss::foo2()))
.根据错误,
noexcept
声明的bar2
评估为noexcept(false)
,然后将其视为与noexcept(noexcept(MyClasss::foo2()))
的不匹配。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.