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

时间:2017-12-31 10:13:55

标签: 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;

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

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

2 个答案:

答案 0 :(得分:14)

[dcl.constexpr]/9

  

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

[basic.link]/3.2

  

具有命名空间范围的名称具有内部链接,如果它是

的名称      

-a 非内联变量的非易失性 const-qualified 类型,既未明确声明为extern,也未声明为具有外部链接

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

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

如果is_integral_v不在内线,可能会发生轻易违反one definition rule的情况。

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()的两个定义不同,这违反了一个定义规则。

答案 1 :(得分:9)

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

变量模板 specialization 是一个变量,但是,有一些关于该规则是否为其提供内部链接的问题。这是core issue 1713,其方向是规则不适用。

然而,核心问题1713并未及时解决C ++ 17。所以LWG决定简单地在变量模板上涂抹inline只是为了安全,因为它们也不会受到伤害。