2

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?

Kushal
  • 8,100
  • 9
  • 63
  • 82
tower120
  • 5,007
  • 6
  • 40
  • 88
  • @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? – tower120 Dec 26 '19 at 18:31
  • @francesco That may address the OP's motivation but does not answer the actual question posed. – 1201ProgramAlarm Dec 26 '19 at 18:33
  • Does this answer your question? [Compile-time constant id](https://stackoverflow.com/questions/7562096/compile-time-constant-id) – jww Dec 26 '19 at 23:01

1 Answers1

6

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.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • 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? – tower120 Dec 26 '19 at 18:36
  • Can you edit to add a comment about compilation-unit boundaries and the linker? My hunch is that `component::component_type` would *not* be the same between two `.o` files when linked together, but I don't know enough to be sure. Thanks! – Rob Starling Dec 26 '19 at 18:36
  • 2
    @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. – Yakk - Adam Nevraumont Dec 26 '19 at 19:01
  • Re: same, I mean if libfoo and libbar each had `component` 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? – Rob Starling Dec 27 '19 at 03:38
  • But also, if these things are just symbolic at compile time (before linking), can they still be used in switch statements? – Rob Starling Dec 27 '19 at 03:39
  • 1
    @RobStarling static libraries = the same; dynamic libraries = implementation defined. – tower120 Dec 28 '19 at 17:25