Инициализация статического члена в шаблоне класса

148

Я хотел бы сделать это:

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

но я не могу, потому что something_relevantэто не цельный тип. Это не зависит от T, но существующий код зависит от того, является ли он статическим членом S.

Поскольку S является шаблоном, я не могу поместить определение в скомпилированный файл. Как мне решить эту проблему?

Александр С.
источник
также относится к std::stringтипу
Тревор Бойд Смит
Начиная с c ++ 11 ключевое слово inline изменилось, так что статические переменные могут быть инициализированы в точке объявления. Таким образом, объявление для этого будет выглядеть следующим образом: «inline static doublething_relevant = 1.5;»
@ user8991265 Я считаю, что встроенные переменные доступны начиная с C ++ 17, а не C ++ 11.
zupazt3

Ответы:

196

Просто определите это в шапке:

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

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

Поскольку он является частью шаблона, как и во всех шаблонах, компилятор будет гарантировать, что он определен только один раз.

SBI
источник
4
@sbi: разве это не нарушает одно правило определения?
Александр К.
7
Нет, если мы говорим о шаблонах. В противном случае шаблоны функций тоже будут делать это.
sbi
1
@sbi, @Prasoon: на самом деле Prasoon кажется первым. Но я все еще принимаю sbi из-за комментария о ODR (который был моей главной заботой).
Александр К.
1
@Sbi просто наведите курсор на текст :)
Йоханнес Шауб -
5
@Johannes: Черт возьми, я здесь год, и я этого не знал! Что еще мне не хватает? (Я до сих пор помню стыд, когда обнаружил, что два числа, которые появляются, когда я нажимаю на число голосов, - это не ошибка, а особенность.) <goes_playing>Ух ты, когда я наведу курсор на твое имя, я вижу твоего представителя! Я тоже этого не знал. @Prasoon: Нет, вы правы, я итеративно пришел туда, где он сейчас. (Вот почему я проголосовал за ваш ответ, кстати.)
sbi
37

Начиная с C ++ 17, теперь вы можете объявить статический член inline, который будет определять переменную в определении класса:

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

в прямом эфире: https://godbolt.org/g/bgSw1u

xaxxon
источник
1
Это отличный ответ. Коротко и точно. См. Также en.cppreference.com/w/cpp/language/static#Static_data_members для получения дополнительной информации.
Андре
31

Это будет работать

template <typename T>
 struct S
 {

     static double something_relevant;
 };

 template<typename T>
 double S<T>::something_relevant=1.5;
Прасун Саурав
источник
Я не определил переменную something_relevant (я удалил template<typename T> double S<T>::something_relevant=1.5;)ошибку, вызванную компиляцией. Можете ли вы сказать мне, в чем причина?
Гудман