在常量表达式中调用的“静态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
之前定义的,因此这是完全可以接受的.
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.
但是,g++
给我以下错误:
error: ‘static constexpr bool MyClass::foo()’ called in a constant expression
这无济于事,因为在常量表达式中调用函数的能力是constexpr
的全部要点.
This is...less than helpful, since the ability to call a function in a constant expression is the entire point of constexpr
.
clang++
更有帮助.除了错误消息指出noexcept
的参数必须是常量表达式外,它还表示:
clang++
is a little more helpful. In addition to an error message stating that the argument to noexcept
must be a constant expression, it says:
note: undefined function 'foo' cannot be used in a constant expression
note: declared here
static constexpr bool foo() { return true; }
^
那么...这是一个两遍编译问题吗?是否存在编译器试图在定义任何成员函数之前定义它们的问题? (请注意,在类的上下文之外,两个编译器都不会引发错误.)这让我感到惊讶.直观地讲,我看不出static constexpr
成员函数不能在类内或类外的任何常量表达式中使用的任何原因.
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? (Note that outside of the context of a class, neither compiler throws an error.) This surprises me; 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.
推荐答案
以T.C.在评论中通过一些链接进行了演示,该标准对此尚不明确.使用decltype(memberfunction())
的尾随返回类型也会出现类似的问题.
As T.C. demonstrated with some links in a comment, the standard is not quite clear on this; a similar problem arises with trailing return types using decltype(memberfunction())
.
中心问题是,通常在类成员声明完成后才将其视为类成员.因此,无论foo
是static constexpr
还是它的声明先于bar
的事实,在MyClass
完成之前,都不能认为它在常量表达式中是可用的".
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.
如Shafik Yaghmour指出的 所述,在标准内进行了一些尝试,以避免依赖于成员的顺序在一个类中,并且显然允许原始问题中的示例进行编译会引入排序依赖性(因为foo
必须在bar
之前声明).但是,已经对排序有很小的依赖性,因为尽管在noexcept
内不能调用 函数,但是noexcept
表达式本身可能取决于该类内部的较早声明:
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
). 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:
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的违反,因为此处仅可能存在一个正确的程序.)
(Note that this is not actually a violation of 3.3.7, since there is still only one correct program that is possible here.)
这种行为实际上可能违反了标准; T.C.指出(在下面的评论中)foo
实际上应该在整个类的范围内查找.当首先声明bar
时,g ++ 4.9.2和clang ++ 3.5.1都失败,并显示错误,但是当首先声明foo
时,编译时没有错误或警告. clang ++主干修订版238946(从3.7.0版本发布不久开始)在第一次声明bar
时 not 不会失败; g ++ 5.1仍然会失败.
This behavior may actually be a violation of the standard; T.C. points out (in a comment below) that foo
here should actually be looked up in the scope of the whole class. 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. clang++ trunk-revision 238946 (from shortly before the release of 3.7.0) does not fail when bar
is declared first; g++ 5.1 still fails.
有趣的是,以下变化会导致clang ++出现不同的异常说明符",而导致g ++出现 not :
Intriguingly, the following variation causes a "different exception specifier" with clang++ but 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()))
不匹配.
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()))
.
这篇关于在常量表达式中调用的“静态constexpr"函数是...错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!