当前位置: 首页 > 知识库问答 >
问题:

为什么非静态数据成员不能是constexpr?

韩华美
2023-03-14

这是有效代码:

struct S {
  constexpr S(int x, int y): xVal(x), yVal(y) {}
  constexpr S(int x): xVal(x) {}
  constexpr S() {}

  const int xVal { 0 };
  const int yVal { 0 };
};

但是在这里,我真的很想声明xValyVal就像这样:

struct S {
  constexpr S(int x, int y): xVal(x), yVal(y) {}
  constexpr S(int x): xVal(x) {}
  constexpr S() {}

  constexpr int xVal { 0 };         // error!
  constexpr int yVal { 0 };         // error!
};

如上所述,代码无法编译。原因是(根据7.1.5/1),只有静态数据成员可以声明为< code>constexpr。但是为什么呢?

共有1个答案

程凯定
2023-03-14

想想< code>constexpr是什么意思。这意味着我可以在编译时解析这个值。

因此,类的成员变量本身不能是< code>constexpr...< code>xVal所属的实例直到实例化时才存在!拥有< code>xVal的对象可以是< code>constexp,这将使< code>xVal成为< code>constexpr,但是< code>xVal本身不可能是< code>constexpr。

这并不意味着这些值不能是常量表达式......实际上,该类的 constexpr 实例可以将变量用作 const 表达式:

struct S {
  constexpr S(int x, int y): xVal(x), yVal(y) {}
  constexpr S(int x): xVal(x) {}
  constexpr S() {}

  int xVal { 0 };
  int yVal { 0 };
};

constexpr S s;

template <int f>//requires a constexpr
int foo() {return f;}

int main()
{
   cout << "Hello World" << foo<s.xVal>( )<< endl; 

   return 0;
}

编辑:所以下面有很多讨论回顾了这里有一些隐含的问题。

以以下示例为例:

//a.h
struct S;
struct A {std::unique_ptr<S> x; void Foo(); A();/*assume A() tries to instantiate an x*/}

//main.cpp

int main(int argc, char** argv) {
  A a;
  a->foo();
}


//S.h
struct S {
  constexpr S(int x, int y): xVal(x), yVal(y) {}
  constexpr S(int x): xVal(x) {}
  constexpr S() {}

  constexpr int xVal { 0 };         // error!
  constexpr int yVal { 0 };
};

A和S的定义可能在完全不同的编译单元中,因此S必须是的事实可能直到链接时才知道,特别是如果忘记了A的实现。这种模棱两可的情况很难调试和实现。更糟糕的是,S的接口可能完全暴露在共享库、COM接口等中……这可能会完全改变共享库的所有基础设施,这可能是不可接受的。

另一个原因是它的传染性。如果类的任何成员都是constexpr,那么所有成员(及其所有成员)和所有实例都必须是constexprr。采用以下场景:

//S.h
struct S {
  constexpr S(int x, int y): xVal(x), yVal(y) {}
  constexpr S(int x): xVal(x) {}
  constexpr S() {}

  constexpr int xVal { 0 };         // error!
  int yVal { 0 };
};

S的任何实例都必须是< code>constexpr,以便能够专门保存< code > const expr < code > xval 。< code>yVal本质上成为< code>constexpr,因为< code > xfal 是。没有任何技术上的编译器原因让你不能这么做(我不这么认为),但是感觉不太像C语言

大概除了标准委员会之外,没有人认为这是个好主意。就我个人而言,我觉得它没什么用处...我并不是真的想定义人们如何使用我的类,只是定义当他们使用我的类时我的类的行为。当他们使用它时,他们可以将特定的实例声明为constexpr(如上)。如果我有一些需要constexpr实例的代码块,我会用模板来完成:

template <S s>
function int bar(){return s.xVal;}

int main()
{
   cout << "Hello World" << foo<bar<s>()>( )<< endl; 

   return 0;
}

虽然我认为你最好使用一个constexpr函数,它可以以限制性和非限制性的方式使用?

constexpr int bar(S s) { return s.xVal; }
 类似资料:
  • 问题内容: 我知道创建一个非静态内部类对象需要一个外部类对象,而创建的非静态内部类对象会自动具有对该外部类对象的隐藏引用。但是为什么非静态内部类不能具有静态成员呢?Java设计人员只需要禁止在内部类的静态方法内访问非静态外部类字段,这样做会更有意义,不是吗? 如果在内部类中具有静态成员没有意义,那么为什么内部类可以通过继承具有静态成员的类来继承静态成员? 我也读了这篇文章。如前所述: 内部类可以继

  • 问题内容: Java教程说,由于内部类与封闭类的实例相关联,所以它(内部类)本身不能定义任何静态成员。 对我来说很有趣,为什么内部类不能声明静态成员,例如某个字段,该内部类的实例可能会与同一内部类的其他实例共享这些成员?这仅仅是Java中必须被视为理所当然的事情的实现吗? 问题答案: 基本上只是一个任意决定。我们没有理由也 不可能 得到支持,但还算不上什么好的理由 来 支持它。只需在外部类中声明静

  • 本文向大家介绍在一个静态方法内调用一个非静态成员为什么是非法的?相关面试题,主要包含被问及在一个静态方法内调用一个非静态成员为什么是非法的?时的应答技巧和注意事项,需要的朋友参考一下 由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非静态变量,也不可以访问非静态变量成员。

  • 本文向大家介绍什么是C#中的静态成员函数?,包括了什么是C#中的静态成员函数?的使用技巧和注意事项,需要的朋友参考一下 静态函数只能访问静态变量。静态函数甚至在创建对象之前就已存在。 将静态函数设置为- 以下是演示静态函数用法的示例- 示例 输出结果

  • 本文向大家介绍Java类的静态成员是什么?,包括了Java类的静态成员是什么?的使用技巧和注意事项,需要的朋友参考一下 在Java中,静态成员是属于该类的成员,您可以在不实例化该类的情况下访问这些成员。 static关键字可以与方法,字段,类(内部/嵌套),块一起使用。 静态方法-您可以使用关键字static创建静态方法。静态方法只能访问静态字段,方法。要访问静态方法,无需实例化该类,只需将类名用

  • 本文向大家介绍什么是C#类的静态成员?,包括了什么是C#类的静态成员?的使用技巧和注意事项,需要的朋友参考一下 我们可以使用static关键字将类成员定义为static。当我们将一个类的成员声明为静态成员时,这意味着无论创建了多少个该类的对象,静态成员只有一个副本。 关键字static表示该类仅存在成员的一个实例。静态变量用于定义常量,因为可以通过调用该类而不创建其实例来检索其值。静态变量可以在成