Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ constexpr使用静态函数初始化静态成员 要求_C++_Gcc_G++_Static Members_Constexpr - Fatal编程技术网

C++ constexpr使用静态函数初始化静态成员 要求

C++ constexpr使用静态函数初始化静态成员 要求,c++,gcc,g++,static-members,constexpr,C++,Gcc,G++,Static Members,Constexpr,我需要一个从constexpr函数计算的constexpr值(即编译时常数)。我希望这两个函数的作用域都是类的名称空间,即静态方法和类的静态成员 第一次尝试 我第一次写这封信的方式很明显: class C1 { constexpr static int foo(int x) { return x + 1; } constexpr static int bar = foo(sizeof(int)); }; g++-4.5.3-std=gnu++0x说: error: ‘static in

我需要一个从
constexpr
函数计算的
constexpr
值(即编译时常数)。我希望这两个函数的作用域都是类的名称空间,即静态方法和类的静态成员

第一次尝试 我第一次写这封信的方式很明显:

class C1 {
  constexpr static int foo(int x) { return x + 1; }
  constexpr static int bar = foo(sizeof(int));
};
g++-4.5.3-std=gnu++0x
说:

error: ‘static int C1::foo(int)’ cannot appear in a constant-expression
error: a function call cannot appear in a constant-expression
g++-4.6.3-std=gnu++0x
投诉:

error: field initializer is not constant
第二次尝试 好吧,我想,也许我得把东西搬出教室。因此,我尝试了以下方法:

class C2 {
  constexpr static int foo(int x) { return x + 1; }
  constexpr static int bar;
};
constexpr int C2::bar = C2::foo(sizeof(int));
g++-4.5.3
将毫无怨言地编译该文件。不幸的是,我的另一个代码对循环使用了一些基于范围的
,所以我必须至少使用4.6。现在我仔细看一下,似乎
constexpr
也需要4.6。通过
g++-4.6.3

3:24: error: constexpr static data member ‘bar’ must have an initializer
5:19: error: redeclaration ‘C2::bar’ differs in ‘constexpr’
3:24: error: from previous declaration ‘C2::bar’
5:19: error: ‘C2::bar’ declared ‘constexpr’ outside its class
5:19: error: declaration of ‘const int C2::bar’ outside of class is not definition [-fpermissive]
这听起来真奇怪。这里的
constexpr
有什么不同?我不想添加
-fpermissive
,因为我更喜欢严格检查我的其他代码。将
foo
实现移到类主体之外没有明显的效果

预期答案 有人能解释一下这是怎么回事吗?我如何才能实现我正在尝试的目标?我主要对以下类型的答案感兴趣:

  • 在gcc-4.6中实现此功能的方法
  • 观察到以后的gcc版本可以正确处理其中一个版本
  • 一个指向规范的指针,根据它我的至少一个构造应该工作,这样我就可以让gcc开发人员知道如何让它真正工作
  • 根据规范,我想要的信息是不可能的,最好是对这一限制背后的原理有一些见解
其他有用的答案也很受欢迎,但可能不会那么容易被接受
#include <iostream>

class C1 
{
public:
    constexpr static int foo(constexpr int x)
    { 
        return x + 1;
    }

    static constexpr int bar;
};

constexpr int C1::bar = C1::foo(sizeof(int));

int main()
{
    std::cout << C1::bar << std::endl;
    return 0;
}
C1类 { 公众: constexpr静态int foo(constexpr int x) { 返回x+1; } 静态constexpr整型条; }; constexpr int C1::bar=C1::foo(sizeof(int)); int main() { 标准::cout标准要求(第9.4.2节):

文本类型的
static
数据成员可以在类定义中用
constexpr
说明符声明;如果是这样,其声明应指定一个大括号或相等的初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是常量表达式

在您的“第二次尝试”和Ilya答案中的代码中,声明没有大括号或相等的初始值设定项

您的第一个代码是正确的。不幸的是GCC4.6不接受它,我不知道在哪里可以方便地尝试4.7.x(例如,ideone.com仍然停留在GCC4.5上)

这是不可能的,因为不幸的是,标准禁止在类已完成的任何上下文中初始化静态
constepr
数据成员。9.2p2中大括号或相等初始值设定项的特殊规则仅适用于非静态数据成员,但这是静态的

最可能的原因是
constepr
变量必须作为编译时常量表达式从成员函数体内部提供,因此变量初始值设定项在函数体之前完全定义,这意味着函数仍然不完整(未定义)在初始值设定项的上下文中,然后此规则生效,使表达式不是常量表达式:

constepr
函数或
constepr
构造函数的定义之外调用未定义的
constepr
函数或未定义的
constepr
构造函数

考虑:

class C1
{
  constexpr static int foo(int x) { return x + bar; }
  constexpr static int bar = foo(sizeof(int));
};
1) Ilya的示例应该是无效的代码,因为静态constexpr数据成员栏的初始化不符合标准中的以下语句:

9.4.2[class.static.data]p3:…可以使用constexpr说明符在类定义中声明文本类型的静态数据成员; 如果是,其声明应在 其中每个作为赋值表达式的初始值设定项子句都是 恒定表达式

2) MvG问题中的代码:

class C1 {
  constexpr static int foo(int x) { return x + 1; }
  constexpr static int bar = foo(sizeof(int));
};
就我所见,它是有效的,直观地说,人们希望它能够工作,因为静态成员foo(int)是由bar开始处理的时间定义的(假设是自顶向下处理)。 一些事实:

  • 我同意C1类在调用foo时并不完整(基于9.2p2)但C1类的完整性或不完整性并不能说明就标准而言是否定义了foo
  • 我在标准中搜索了成员函数的定义,但没有找到任何结果
  • 因此,如果我的逻辑正确,Ben提到的陈述在这里不适用:

    调用未定义的constexpr函数或未定义的 constexpr函数定义之外的constexpr构造函数 或constexpr构造函数
3) Ben给出的最后一个例子简化了:

看起来无效,但原因不同,不仅仅是因为在bar的初始值设定项中调用了foo。逻辑如下:

  • foo()是在静态constexpr成员栏的初始值设定项中调用的,因此它必须是一个常量表达式(按9.4.2 p3)
  • 由于它是对constexpr函数的调用,因此函数调用替换(7.1.5p5)起作用
  • 它们不是函数的参数,所以剩下的是“隐式地将结果返回的表达式或带括号的init列表转换为函数的返回类型,就像通过复制初始化一样。”(7.1.5 p5)
  • 返回表达式就是bar,它是一个左值,需要左值到右值的转换
  • 但第9号子弹(5.19 p2)
    class C1
    {
      constexpr static int foo() { return bar; }
      constexpr static int bar = foo();
    };
    
    constexpr int fooext(int x) { return x + 1; }
    struct C1 {
      constexpr static int foo(int x) { return x + 1; }
      constexpr static int bar = fooext(5);
    };
    
    constexpr static int barext = C1::foo(5);