Why does cppreference define type_traits xxx_v sho

2019-01-25 05:48发布

Why does cppreference define type_traits xxx_v shortcuts as inline constexpr and not just constexpr?

For example, see is_integral_v:

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

Is this just a matter of style or is there some difference in behavior? As far as I know constexpr variables are implicitly inline.

Edit: Looking at the draft of the latest standard, it also uses inline constexpr. The question actually applies to the standard, then.

2条回答
forever°为你锁心
2楼-- · 2019-01-25 06:10

[dcl.constexpr]/9

A constexpr specifier used in an object declaration declares the object as const.

[basic.link]/3.2

A name having namespace scope has internal linkage if it is the name of

-a non-inline variable of non-volatile const-qualified type that is neither explicitly declared extern nor previously declared to have external linkage

Without inline specifier, is_integral_v would have internal linkage. This could be problematic if you compared two pointers to this same variable name taken in different translation unit.


Nota Bene: the inline specifier is redundant with constexpr only if the variable is a class static data member.


Following an exemple of easy violation of the one definition rule that could happen if is_integral_v where not inline.

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

In the two translation units, the variable bad_is_integral_v is instantiated as separate static variables. The inline function g() is defined in these two translation units. Inside the definition of g(), the variable bad_is_integral_v is ODR used, so the two definitions of g() are different, which is a violation of the one definition rule.

查看更多
▲ chillily
3楼-- · 2019-01-25 06:20

[basic.link]/3.2 applies to names of "a non-inline variable of non-volatile const-qualified type". A variable template isn't a variable, just like a class template isn't a class, a function template isn't a function, and a cookie cutter isn't a cookie. So that rule doesn't apply to the variable template is_integral_v itself.

A variable template specialization is a variable, however, so there are some questions about whether that rule gives it internal linkage. This is core issue 1713, the direction of which is that the rule is not applicable.

Core issue 1713, however, wasn't resolved in time for C++17. So LWG decided to simply plaster inline all over the variable templates just to be safe, because they don't hurt, either.

查看更多
登录 后发表回答