Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing static constexpr variables and classes inside a struct

Here is my working code example:

#include <iostream>

template<typename B>
class b {
public:
    int y;

    constexpr b(int x) : y(x) {

    }

    constexpr void sayhi() {
        std::cout << "hi" << std::endl;
    }
};



template<int x>
struct A {
    static constexpr b<int> bee = x;
    static constexpr int y = x;         // this one is fine and usable already, I don't have to do something like what I did on member bee

    inline static void sayhi() {
        std::cout << y << std::endl;
    }
};

template<int x>
constexpr b<int> A<x>::bee;        // why do I have to do something like this, it will cause errors if I don't.

int main(int argc, char** argv) {
    A<30>::bee.sayhi();             // works fine
    A<30>::sayhi();                 // works fine

    return 0;
}

What my code does is simple, I have template struct A that has two static variables, namely a static constexpr int y and a static constexpr b<int> bee = x;. My template struct A will get the value of the argument which will be copied by x from the template parameter. My question is: how come when it comes to classes, I have to initialize the class by doing something like this:

template<int x>
constexpr b<int> A<x>::bee; 

If I don't use the code above, I get the undefined reference error. Wherein the int is already fine and accessible just from doing something like:

static constexpr int y = x;    

I am concerned why I don't have to forward declare it anymore.

like image 588
Carlos Miguel Colanta Avatar asked Jul 21 '15 05:07

Carlos Miguel Colanta


People also ask

Does constexpr need to be static?

A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later. So, what does constexpr mean?

What can be constexpr?

constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.

Does constexpr take memory?

The alternatives don't have the all of the positives of static constexpr - you're guaranteed compile time processing, type safety, and (potentially) lower usage of memory (constexpr variables don't need to take up memory, they are effectively hard coded unless if possible).

What is a constexpr constructor?

Constant Expression Constructors A constexpr constructor allows the compiler to initialize the object at compile-time, provided that the constructor's arguments are all constant expressions. Formally, a constant expression constructor is one that meets the following criteria: It's declared constexpr explicitly.


1 Answers

A static constexpr member has a value upon its initialization inside the class { } scope, but it does not have a location in memory (an address) until it is defined outside the class { }. The reason is that you may decide to include some or all of its specializations in a link library (e.g. .o or .so), or whether to give effectively-inline linkage to specializations by default.

The out-of-class definition is required if the address of the object is ever used, which implies that it must exist as a global variable. On the other hand, if you want the constexpr member only to exist at compile time, prohibiting global storage allocation, then omitting the definition is a good choice.

By the way, it's not allowed to put the constexpr specifier on a function that can never be evaluated as a constant expression, such as sayhi which prints to std::cout. This is a "no diagnostic required (NDR)" rule, meaning that the compiler might not complain now but the next compiler version might.

like image 84
Potatoswatter Avatar answered Oct 14 '22 02:10

Potatoswatter