Arkady
Arkady

Reputation: 2207

What more does using constexpr gives instead of just static const variables?

As I understand, calculation at compile time means, that at runtime instead of constexpr functions there will be const values (by definition, because they will be already calculated). That touches functions (they already calculated, so, it is just as variable of function type), that touches variables (it is just as static const variable), same with classes.

One plus from constexpr function I see: if in ANSI C, for example, I had to have 5 defines, maybe united logically, now I can write one such function and use it instead of 5 defines, being able to write logic to manipulate of set of constexpr function return values. So, as result I have same set of 5 values, but now I described them logically, writing such function.

But I feel I understand something wrong, because I see such examples:

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) I can understand if constructor without parameters is constexpr. Yes, it is some const state that can be calculated at compile time and use in future, maybe faster. But why constructor with parameters? Object body will be on Stack or on Heap, we don't know which parameters we will put there, what for is it?

(2, 3) Same here, what for is it? How can we calculate at compile time copying of unknown object?

(4, 5) I wonder what for it can be used. Just for object which state was calculated at compile time? Or calling value of some object (that will be created at runtime) from Heap or Stack may costs much and that somehow will speed it on?

Upvotes: 3

Views: 819

Answers (3)

R. Martinho Fernandes
R. Martinho Fernandes

Reputation: 234354

Object body will be on Stack or on Heap, (...)

This is at best irrelevant, and at worst wrong. In the C++ abstract machine the objects will be in some storage location. In a real machine, the objects will be wherever the compiler deems appropriate, and that wherever may even be nowhere.

we don't know which parameters we will put there, what for is it?

If we initialise an object using that constructor with constant expressions for arguments, the initialisation expression will also be a constant expression. Constant expressions are special because they are the only kinds of expressions that can be used in certain particular contexts, like array sizes, or template arguments. Other than counting as a constant expression there is no difference between this and a normal initialisation without constexpr.

How can we calculate at compile time copying of unknown object?

The same as before: if we initialise a copy using a constant expression as the source, the copy will also be a constant expression. Note that constexpr is only about things counting as constant expressions or not. It isn't about when they are evaluated.

I wonder what for it can be used. Just for object which state was calculated at compile time?

See above :) The primary purpose is to allow use of those objects in contexts that require constant expressions.

Upvotes: 1

ecatmur
ecatmur

Reputation: 157314

1: A constexpr constructor that takes parameters can be called at compile time if the parameters are known at compile time. This may be useful to encapsulate state, the same reason we use objects instead of primitive values at run time.

2, 3: Similarly, one can copy a constexpr object at compile time if the original source object is also a compile-time value.

4, 5: constexpr accessors can be called both at run time and at compile time. Run time performance is not directly relevant, except that constexpr methods are implicitly inline and otherwise well-behaved (not containing some undefined behavior) so may be more amenable to optimization.

Upvotes: 1

E_net4
E_net4

Reputation: 29972

You are missing the fact that the use of constexpr in member functions and constructors does not mean that they are always executed in compile-time. They are simply done so when possible.

A few examples for clarity:

  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
      // ...
  }

The same applies to the remaining constructors: the key point is that with constexpr-qualified functions and constructors, if the full arguments list contains constant expressions (and if the object at hand is a constant expression), then the result will also be a constant expression.

The advantage of having constexpr getters is that attributes of constant expressions can be obtained for use in cases where only constant expressions are allowed. A float cannot be used as a template parameter, but assuming the vector was made of ints, you could do this:

  SomeClass<myGlobalVec.x()> anObject;

Upvotes: 3

Related Questions