I know, there are many answered question about linkage of a static (constexpr) members.
But I wonder, why using a template class out-of-line definition works in a header file but not for a specialized class.
a) This works without linker error:
template<typename, typename> struct Foobar; template<typename T> struct Foobar<int, T> { static constexpr std::array<int, 1> a = {{1}}; }; template<typename T> constexpr std::array<int, 1> Foobar<int, T>::a; // foo.cpp std::cout << Foobar<int, int>::a[0] << "\n"; // bar.cpp std::cout << Foobar<int, int>::a[0] << "\n"; The objdump of:
foo.o: 0000000000000000 w O .rodata._Z6FoobarIiiE1aE 0000000000000004 _Z6FoobarIiiE1aE
bar.o: 0000000000000000 w O .rodata._Z6FoobarIiiE1aE 0000000000000004 _Z6FoobarIiiE1aE
Linked file: 0000000000475a30 w O .rodata 0000000000000004 _Z6FoobarIiiE1aE
b) This does not (multiple definition):
template<typename> struct Foobar; template<> struct Foobar<int> { static constexpr std::array<int, 1> a = {{1}}; }; constexpr std::array<int, 1> Foobar<int>::a; // foo.cpp std::cout << Foobar<int>::a[0] << "\n"; // bar.cpp std::cout << Foobar<int>::a[0] << "\n"; The objdump of:
foo.o 0000000000000100 g O .rodata 0000000000000004 _Z6FoobarIiE1aE
bar.o: 0000000000000420 g O .rodata 0000000000000004 _Z6FoobarIiE1aE
What we see, the out-of-line definition has different addresses inside the object files (example b)).
My question to you:
- Is it save to use the template trick? What are the disadvantage?
- Would it be useful to relax the definition of odr for such cases like b in the future?
Thank you in advance!
inline.