为什么cppreference将type_traits xxx_v快捷方式定义为内联constexpr而不仅仅是constexpr?

Dan*_*nra 16 c++ language-lawyer c++17 inline-variable

为什么cppreference定义type_traits xxx_v快捷方式inline constexpr而不仅仅是constexpr

例如,请参阅is_integral_v:

template< class T >
inline constexpr bool is_integral_v = is_integral<T>::value;
Run Code Online (Sandbox Code Playgroud)

这只是风格问题还是行为有所不同?据我所知,constexpr变量是隐含的inline.

编辑:查看最新标准的草案,它也使用inline constexpr.那么问题实际上适用于标准.

Oli*_*liv 14

[dcl.constexpr]/9

对象声明中使用的constexpr说明符将对象声明为const.

[basic.link] /3.2

具有命名空间作用域的名称具有内部链接(如果它的名称)

- 非易失性const限定类型的非内联变量,既未显式声明为extern,也未声明为具有外部链接

没有inline说明符,is_integral_v就会有内部联系.如果您将两个指针与在不同翻译单元中采用的相同变量名称进行比较,则可能会出现问题.


Nota Bene:只有当变量是类静态数据成员时,内联说明符才与constexpr冗余.


遵循一个简单违反一个定义规则的例子,如果is_integral_v不是内联的话可能会发生.

bad_type_trait.h

template<class T>
constexpr auto bad_is_integral_v=std::is_integral<T>::value;
Run Code Online (Sandbox Code Playgroud)

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.
  }
Run Code Online (Sandbox Code Playgroud)

source1.cpp

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

source2.cpp

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

在两个转换单元中,变量bad_is_integral_v被实例化为单独的静态变量.内联函数g()在这两个翻译单元中定义.在定义中g(),变量bad_is_integral_v是使用的ODR,因此两个定义g()是不同的,这违反了一个定义规则.

  • 但是你知道.这提出了另一个有趣的问题.为什么人们会采用类型特征的地址不变? (3认同)
  • 或者也许没有人期望人们拿到地址.由于`std :: xxx <> :: value`由于是静态数据成员而内联,因此`xxx_v`版本也是内联的,以便更接近它.这可能只是一致性问题. (3认同)
  • @StoryTeller也许将它传递给一些带有转发引用的通用函数模板? (2认同)
  • 我不相信这句话实际上是适用的.`is_integral_v`是变量模板的名称.变量模板不是变量. (2认同)

T.C*_*.C. 10

[basic.link] /3.2适用于" 非易失性const限定类型的非内联变量 "的名称.变量模板不是变量,就像类模板不是类,函数模板不是函数,cookie切割器不是cookie.因此该规则不适用于变量模板is_integral_v本身.

可变模板专业化是一个变量,然而,也有这个规矩是否赋予了它内在联系的一些问题.这是核心问题1713,其方向是该规则不适用.

然而,核心问题1713并没有及时解决C++ 17.因此,LWG决定简单地将inline所有可变模板涂抹在墙上以保证安全,因为它们也不会受到伤害.