3

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?

3
  • @francesco partilally, I still don't understand how compiler can know member address beforehand. And what happens across dll bounadaries? Each dll will have its own unique address for the same type/member? Commented Dec 26, 2019 at 18:31
  • @francesco That may address the OP's motivation but does not answer the actual question posed. Commented Dec 26, 2019 at 18:33
  • Does this answer your question? Compile-time constant id Commented Dec 26, 2019 at 23:01

1 Answer 1

7

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.

Sign up to request clarification or add additional context in comments.

6 Comments

Nice, I forgot to ask - what happens across dll boundaries? Each dll will have its own unique address for the same static member, or they will be the same?
Can you edit to add a comment about compilation-unit boundaries and the linker? My hunch is that component<int>::component_type would not be the same between two .o files when linked together, but I don't know enough to be sure. Thanks!
@robs what do you mean by the same? It is (implicitly) an inline variable. And inline variables are the same between compilation units. Dlls are not covered by the standard, so it will be platform dependent what is going to happen.
Re: same, I mean if libfoo and libbar each had component<int> and each had a function to expose its component_type and you (statically) linked a program with both, would the functions return the same value at runtime?
@RobStarling static libraries = the same; dynamic libraries = implementation defined.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.