22

为什么 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. 那么这个问题实际上适用于标准。

4

2 回答 2

15

[dcl.constexpr]/9

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

[basic.link]/3.2

具有命名空间范围名称如果是

-非 volatile const 限定类型的非内联变量,既没有显式声明 extern,也没有先前声明为具有外部链接

没有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.
  }

源1.cpp

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

源代码2.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()是不同的,这违反了一个定义的规则。

于 2017-12-31T10:35:39.373 回答
12

[basic.link]/3.2 适用于“非易失性 const 限定类型的非内联变量”的名称。变量模板不是变量,就像类模板不是类,函数模板不是函数,千篇一律不是 cookie 一样。因此该规则不适用于变量模板is_integral_v本身。

然而,变量模板化是一个变量,因此存在一些关于该规则是否赋予它内部链接的问题。这是核心问题1713,方向是规则不适用。

然而,核心问题 1713 并没有在 C++17 中得到及时解决。因此,LWG 决定简单地inline在变量模板上贴上石膏,以确保安全,因为它们也不会造成伤害。

于 2018-01-03T13:33:54.823 回答