使用constexpr而不仅仅是静态const变量还有什么呢?

时间:2014-07-14 16:08:39

标签: c++ c++11 constexpr

据我所知,编译时的计算意味着,在运行时而不是constexpr函数会有const值(根据定义,因为它们已经被计算)。 它触及函数(它们已经计算,因此,它只是函数类型的变量),触及变量(它只是作为静态const变量),与类相同。

我看到constexpr函数的一个优点:例如,如果在ANSI C中,我必须有5个定义,也许逻辑上是统一的,现在我可以编写一个这样的函数并使用它代替5个定义,能够编写逻辑操纵constexpr函数返回值的集合。所以,结果我有相同的5个值,但现在我在逻辑上描述了它们,写了这样的函数。

但是我觉得我理解错了,因为我看到了这样的例子:

class vec3 {
        union {
                struct {
                        float _x, _y, _z;
                };
                float _v[3];
        };

public:
        constexpr vec3(): _x(0), _y(0), _z(0) {} // 
        constexpr vec3(float x, float y, float z): _x(x), _y(y), _z(z) {}(1)
        constexpr vec3(const vec3&) = default; // (2)
        vec3 &operator=(const vec3&) = default; // (3)
        constexpr float x() { return _x; } // (4)
        constexpr float y() { return _y; }
        constexpr float z() { return _z; }
        constexpr const float *v() { return _v; } // (5)
        float *v() { return _v; }
};

(1)我可以理解没有参数的构造函数是否为constexpr。是的,它是一些const状态,可以在编译时计算并在将来使用,也许更快。但为什么构造函数有参数?对象体将在Stack或Heap上,我们不知道我们将放在哪个参数,它是什么?

(2,3)同样,这是什么?我们怎样才能在编译时计算出未知对象的复制?

(4,5)我想知道它可以用什么。仅针对在编译时计算状态的对象?或者从Heap或Stack中调用某个对象的值(将在运行时创建)可能会花费很多,而且会以某种方式加速它?

3 个答案:

答案 0 :(得分:3)

您错过了在成员函数和构造函数中使用constexpr并不意味着它们总是在编译时执行的事实。它们只是在可能的情况下完成。

为清晰起见,举几个例子:

  constexpr vec3 myGlobalVec{1,2,3}; // uses vec3(x,y,z) in compile time
  constexpr vec3 copyOfGlobalVec = myGlobalVec; // uses copy constructor in compile time

  void foo(int n) {
      vec3 my(n,n,n); // uses the same constructor, but invoked in runtime
      // ...
  }

这同样适用于其余的构造函数:关键点是使用constexpr - 限定函数和构造函数,如果完整参数列表包含常量表达式(如果手头的对象是常量表达式),那么结果也将是一个不变的表达。

拥有constexpr getter的优点是可以获得常量表达式的属性,以便在只允许使用常量表达式的情况下使用。 float不能用作模板参数,但假设向量由int s组成,则可以执行此操作:

  SomeClass<myGlobalVec.x()> anObject;

答案 1 :(得分:1)

1:如果参数在编译时已知,则可以在编译时调用带有参数的constexpr构造函数。这可能对封装状态很有用,这与我们在运行时使用对象而不是原始值的原因相同。

2,3:同样,如果原始源对象也是编译时值,则可以在编译时复制constexpr对象。

4,5:constexpr访问器可以在运行时和编译时调用。运行时性能并不直接相关,除了constexpr方法隐式内联且行为良好(不包含某些未定义的行为),因此可能更适合优化。

答案 2 :(得分:1)

  

对象主体将位于堆栈或堆上,(...)

这至多无关紧要,最糟糕的是错误。在C ++抽象机器中,对象将位于某个存储位置。在真实的机器中,对象将在编译器认为合适的任何地方,甚至可能无处

  

我们不知道我们将在那里放置哪些参数,它是什么?

如果我们使用具有参数的常量表达式的构造函数初始化对象,则初始化表达式也将是常量表达式。常量表达式是特殊的,因为它们是可以在某些特定上下文中使用的唯一种类的表达式,如数组大小或模板参数。除了计算为常量表达式之外,在没有constexpr的正常初始化之间没有差异

  

我们如何在编译时计算未知对象的复制?

与之前相同:如果我们使用常量表达式作为源初始化副本,则副本也将是常量表达式。请注意,constexpr仅与计算为常量表达式的事物有关。 It isn't about when they are evaluated

  

我想知道它可以用什么。仅针对在编译时计算状态的对象?

见上文:)主要目的是允许在需要常量表达式的上下文中使用这些对象。