在常量表达式中调用的“静态constexpr"函数是...错误? [英] `static constexpr` function called in a constant expression is...an error?

查看:504
本文介绍了在常量表达式中调用的“静态constexpr"函数是...错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

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()).

中心问题是,通常在类成员声明完成后才将其视为类成员.因此,无论foostatic 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆