Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I initialize a `constexpr static` member outside the class?

Tags:

c++

I'm working with a variable-width communications format. The structs to handle it look something like this:

struct Header
{
  int msgType = -1, len;

  Header() { len = sizeof(*this); }
};

struct A : public Header
{
  int x; char y;

  A() { msgType = 1; len = sizeof(*this); }
};

// Further structs B, C, ... declared along the same lines

I would like to have a constexpr static member Header::MAX_SIZE which gives the max size of any of these derived classes, e.g. so I can allocate a buffer which is guaranteed to hold any such packet. So I'd like to do something like

struct Header
{
  int msgType = -1, len;

  constexpr static std::size_t MAX_SIZE;

  Header() { len = sizeof(*this); }
};

// ... declaration of subclasses ...

inline Header::MAX_SIZE = std::max({ sizeof(A), sizeof(B), sizeof(C) });

I need the definition to come outside of the class because it depends on sizeof(A), etc., which in turn depend on the definition of Header.

It seems like this sort of thing should be unobjectionable: I'm giving the definition of the member in the same source file, and it can be computed at compile time. But I haven't found any way to tell the compiler to actually do this.

like image 813
Daniel McLaury Avatar asked Apr 28 '21 12:04

Daniel McLaury


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 is constexpr in C ++ 11?

The keyword constexpr was introduced in C++11 and improved in C++14. It means constant expression. Like const , it can be applied to variables: A compiler error is raised when any code attempts to modify the value. Unlike const , constexpr can also be applied to functions and class constructors.

Do constexpr variables 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).

How to declare a constant initializer for a static data member?

If a static data member is of const integral or const enumeration type, you may specify a constant initializer in the static data member's declaration. This constant initializer must be an integral constant expression.

Can static data members appear in integral constant expressions?

If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions.

What is constexpr int const&x = 42?

static constexpr int const& x = 42; // constexpr reference to a const int object // (the object has static storage duration // due to life extension by a static reference) Even though try blocks and inline assembly are allowed in constexpr functions, throwing exceptions or executing the assembly is still disallowed in a constant expression.

What is a constexpr specifier in C++?

A constexpr specifier used in an object declaration or non-static member function (until C++14) implies const. A constexpr specifier used in a function or static data member (since C++17) declaration implies inline. If any declaration of a function or function template has a constexpr specifier, then every declaration must contain that specifier.


Video Answer


1 Answers

constexpr goes on the initializing declaration of a variable, so just put it outside the class:

struct Header
{
  int msgType = -1, len;

  static const std::size_t MAX_SIZE;

  Header() { len = sizeof(*this); }
};

// ... declaration of subclasses ...

inline constexpr std::size_t Header::MAX_SIZE = std::max({ sizeof(A), sizeof(B), sizeof(C) });

Note that the implicit const must be spelled out in the declaration. The definition should go in the same header to avoid any translation unit seeing the declaration but not the inline, which is not allowed.

like image 56
Davis Herring Avatar answered Sep 17 '22 12:09

Davis Herring