tower120
tower120

Reputation: 5265

constexpr pointer to constexpr static member in C++17

In the following code, I'm taking address to static constexpr member:

struct component_type_data{};

template<class Derived>
class component{
    private:
    const constexpr static component_type_data type_data{};
    public:
    static constexpr const component_type_data* component_type = &type_data;
};

My motivation is to have compile time unique id for type.

Is this valid? Code compiles only starting from C++17. And I can use that pointer as template argument.

If this valid, how compiler can know address beforehand?

UPDATE :

Also, what happens across dll boundaries? Each dll will have its own unique address for the same static member, or they will be the same?

Upvotes: 3

Views: 831

Answers (1)

Brian Bi
Brian Bi

Reputation: 119487

Is this valid?

Yes; a constexpr pointer object is allowed to contain the address of any object of static storage duration.

Code compiles only starting from C++17.

Prior to C++17, static constexpr data members require an out-of-class definition as well:

template <class Derived>
constexpr const component_type_data component<Derived>::type_data;

template <class Derived>
constexpr const component_type_data* component<Derived>::component_type;

If this valid, how compiler can know address beforehand?

If you mean the numerical address: the answer is that the compiler cannot, in general, know that, as it may not be assigned until link time or possibly even until the program is loaded by the operating system.

However, the reason why addresses can be used as constant expressions is that the compiler effectively represents them symbolically, i.e., "address of component<int>::type_data". If you were to then dereference such a pointer at compile time, the compiler would know that the result is "lvalue referring to component<int>::type_data". So compile-time computation in C++ is really quite complicated and involves a lot of metadata (in the post-C++17 world, we really expect a lot from our compilers). Note that once you attempt to examine the numerical address (i.e., using reinterpret_cast) you no longer have something that is usable at compile time.

Upvotes: 7

Related Questions