190

I'd like to do this:

template <typename T>
struct S
{
    ...
    static double something_relevant = 1.5;
};

but I can't since something_relevant is not of integral type. It doesn't depend on T, but existing code depends on it being a static member of S.

Since S is template, I cannot put the definition inside a compiled file. How do I solve this problem ?

sbi
  • 219,715
  • 46
  • 258
  • 445
Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
  • also applies to `std::string` type – Trevor Boyd Smith Jul 09 '18 at 12:49
  • Since c++11 the keyword inline has changed so that static variables can be initialized at the point of declaration. So the declaration for this would look like "inline static double something_relevant = 1.5;" –  Apr 03 '19 at 14:27
  • @user8991265 I believe inline variables are available since C++17, not C++11. – zupazt3 Apr 20 '20 at 10:49

3 Answers3

248

Just define it in the header:

template <typename T>
struct S
{
    static double something_relevant;
};

template <typename T>
double S<T>::something_relevant = 1.5;

Since it is part of a template, as with all templates the compiler will make sure it's only defined once.

sbi
  • 219,715
  • 46
  • 258
  • 445
  • 7
    @sbi: doesn't it violate the one definition rule ? – Alexandre C. Jul 12 '10 at 15:49
  • 12
    No, not if we're talking templates. Otherwise function templates would do so, too. – sbi Jul 12 '10 at 15:51
  • 1
    @sbi, @Prasoon: actually Prasoon seems to be the first. But I still accept sbi's because of the comment about the ODR (which was my primary concern). – Alexandre C. Jul 12 '10 at 16:00
  • @Johannes: How do you get at the exact times? For me, it just shows "1 hour ago" each. I know I can sort them by "oldest" and "newest", and it will show the exact times in three days (until then it says "2 days ago"), but I have no idea how I get at the exact times _now_. – sbi Jul 12 '10 at 17:06
  • 2
    @sbi just hover over the text :) – Johannes Schaub - litb Jul 12 '10 at 17:20
  • @Johannes Schaub -litb: Frankly speaking when I saw sbi's answer the last two lines were `template double something_relevant = 1.5;` which is syntactically incorrect(he might have missed something );-). So I decided to post my solution. – Prasoon Saurav Jul 12 '10 at 17:26
  • @sbi: If you think there's something wrong in my last comment, please do mention :-) – Prasoon Saurav Jul 12 '10 at 17:35
  • 6
    @Johannes: Dammit, I'm here for a year and I didn't know that! What else am I missing? (I still remember the shame when I discovered that the two numbers that appear when I click on the number of votes aren't a bug, but a feature.) `` Wow, when I hover over your name, I see your rep! I didn't know that one either. @Prasoon: No, you're right, I iteratively arrived at where it is now. (That's why I up-voted your answer, BTW.) – sbi Jul 12 '10 at 18:43
  • 1
    @Johannes: Ah, I always wondered what that stood for.(And, yes, Imagine is a wonderful song.) @James: That rang a bell: ["My hair style calls into immediate question all my judgements."](http://groups.google.de/group/comp.lang.c++.moderated/msg/f7e901ce6e8a86c0) (near the end of that posting) – sbi Jul 13 '10 at 13:45
  • What if class is enclosed into namespace? – fnc12 Apr 07 '17 at 10:42
  • @fnc12: Then you need to put stuff into said namespace? – sbi Apr 30 '17 at 21:03
  • 1
    @sbi - To muddy the waters, how do we initialize 5 or 6 specializations of `T`? I've been trying the {simple|obvious} answer at [How to initialize a static member of a parametrized-template class](https://stackoverflow.com/q/11153182/608639), but Clang keeps failing the link due to mulitply defined symbols because the header is used in several source files. In our case the class variable is `static const` and it is like things are escaping translation unit scope. – jww Dec 25 '17 at 22:31
  • 1
    @jww: If you define static members of specific instances, rather than the base template's, you will have to put them into cpp files. There's tricks around this, but they add hard-to-read warts to your code. – sbi Jan 01 '18 at 07:07
  • if multiple cpp includes this header, and in each of the cpp, instantiation `S` of `T=int` happens in each TU, will they share the same static `S::something_relevant`? Isn't each TU has its own definition of the `S::something_relevant`? – dragonxlwang Jan 16 '21 at 08:42
  • @dragonxlwang: Your compiler/linker is required to fold all these instances from different translation units into a single one in the same way it is required to fold all the functions generated from function templates in each translation unit. – sbi Mar 30 '21 at 20:19
  • Imagine I have 5 template arguments with SFINAE stuff and 10 static members. Is there a way to not repeat the whole template<...> thing? – Osman-pasha Aug 31 '21 at 05:57
  • 1
    @Osman-pasha Nope, there isn't. It's a pain in the neck to write this. – sbi Sep 14 '21 at 10:17
  • @sbi what if the static member to be initialized is private ? – Bemipefe Nov 21 '22 at 14:41
  • @Bemipefe Then it cannot be accessed from outside the class (except for friendship)? Why do you ask? – sbi Nov 24 '22 at 22:33
  • @sbi My concern was not being able to initialize a __private static__ member like you suggested (from "outside" the class) but surprisingly your code works also in this case. – Bemipefe Nov 25 '22 at 14:29
  • Oh. I see. Yes, of course it works! This is not considered accessing a private member. You are defining and initializing a previously declared object, and even private objects have to be defined and should be initialized. – sbi Nov 28 '22 at 22:27
80

Since C++17, you can now declare the static member to be inline, which will define the variable in the class definition:

template <typename T>
struct S
{
    ...
    static inline double something_relevant = 1.5;
};

live: https://godbolt.org/g/bgSw1u

xaxxon
  • 19,189
  • 5
  • 50
  • 80
  • 3
    This is an excellent answer. Short and precise. See also https://en.cppreference.com/w/cpp/language/static#Static_data_members for more information. – andreee Dec 05 '18 at 11:00
  • 3
    One wonders why the standards committee felt it necessary to require an extra keyword instead of just making the previously illegal static declaration legal. – Robin Davies Oct 10 '22 at 17:41
39

This will work

template <typename T>
 struct S
 {

     static double something_relevant;
 };

 template<typename T>
 double S<T>::something_relevant=1.5;
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • I didn't define the something_relevant variable(I removed ```template double S::something_relevant=1.5;)``` compiler throwing error.Can you please tell me what is the reason? – goodman Jan 21 '20 at 10:29
  • This will introduce a copy of the variable in each module that include these lines. And how can one make sure that the variable is present only in one shared module, and other modules reference it? – Fedor Jun 24 '21 at 11:10