Почему cppreference определяет ярлыки type_traits xxx_v как встроенный constexpr, а не просто constexpr?

Почему cppreference определяет ярлыки type_traits xxx_v как inline constexpr и не только constexpr?

Например, см. is_integral_v:

template< class T >
inline constexpr bool is_integral_v = is_integral<T>::value;

Это просто вопрос стиля или есть разница в поведении? Насколько я знаю constexpr переменные неявно inline,

Изменить: глядя на проект последнего стандарта, он также использует inline constexpr, Тогда вопрос действительно относится к стандарту.

2 ответа

Решение

[basic.link]/3.2 применяется к именам "не встроенной переменной энергонезависимого типа с константным определением". Переменный шаблон не является переменной, точно так же, как шаблон класса не является классом, шаблон функции не является функцией, а резак печенья не является cookie. Так что это правило не относится к шаблону переменной is_integral_v сам.

Однако переменная специализация шаблона - это переменная, поэтому есть некоторые вопросы о том, дает ли это правило внутреннюю связь. Это основной вопрос 1713, направление которого заключается в том, что правило не применимо.

Основная проблема 1713, однако, не была решена вовремя для C++17. Поэтому LWG решил просто оштукатурить inline во всех шаблонах переменных просто для безопасности, потому что они тоже не вредят.

[dcl.constexpr]/9

Спецификатор constexpr, используемый в объявлении объекта, объявляет объект как const.

[basic.link] /3.2

Имя, имеющее область имен, имеет внутреннюю связь, если это имя

- не встроенная переменная энергонезависимого типа с константной квалификацией, которая явно не объявлена ​​как внешняя и не объявлялась ранее как имеющая внешнюю связь

Без inline спецификатор, is_integral_v будет иметь внутреннюю связь. Это может быть проблематично, если вы сравниваете два указателя с одним и тем же именем переменной, взятой в другой единице перевода.


Примечание: встроенный спецификатор избыточен с constexpr, только если переменная является членом статических данных класса.


После примера легкого нарушения правила одного определения, которое может произойти, если is_integral_v где не в строке.

bad_type_trait.h

template<class T>
constexpr auto bad_is_integral_v=std::is_integral<T>::value;

my_header.h

#include "bad_type_trait.h"
void f(const bool& x);

inline void g()
  {
  f(bad_is_integral_v<int>);
  //g ODR use the static variable bad_is_integral_v.
  //"ODR use" approximate definition is: 
  //     the variable is refered by its memory address.
  }

source1.cpp

#include "my_header.h"
void my_func1(){
   g(); //the definition of g in this translation unit.
   }

source2.cpp

#include "my_header.h"
void my_func2(){
   g(); //is not the same as the definition of g in this translation unit.
   }

В двух единицах перевода переменная bad_is_integral_v создается как отдельные статические переменные. Встроенная функция g() определяется в этих двух единицах перевода. Внутри определения g()переменная bad_is_integral_v используется ODR, поэтому два определения g() разные, что является нарушением правила одного определения.

Другие вопросы по тегам