为什么 cppreference 将 type_traits xxx_v 快捷方式定义为内联 constexpr 而不仅仅是 constexpr?
Why does cppreference define type_traits xxx_v shortcuts as inline constexpr and not just 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
。那么这个问题实际上适用于标准。
A constexpr specifier used in an object declaration declares the object as const.
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
没有 inline
说明符,is_integral_v
将具有内部链接。如果您比较两个指向不同翻译单元中相同变量名的指针,这可能会出现问题。
注意事项:仅当变量是 class 静态数据成员时,内联说明符才与 constexpr 冗余。
下面是一个很容易违反 one definition rule 的例子,如果 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()
的定义里面,使用了ODR变量bad_is_integral_v
,所以g()
的两个定义不一样,违反了一个定义的规则。
[basic.link]/3.2 适用于 "a non-inline variable of non-volatile const-qualified type" 的名称。变量模板不是变量,就像 class 模板不是 class、函数模板不是函数、千篇一律不是曲奇饼一样。因此该规则不适用于变量模板 is_integral_v
本身。
变量模板 specialization 是一个变量,但是,因此对于该规则是否为其提供内部链接存在一些疑问。这是core issue 1713,方向是规则不适用
然而,核心问题 1713 没有及时解决 C++17。所以 LWG 决定简单地在所有变量模板上涂抹 inline
以确保安全,因为它们也不会造成伤害。
为什么 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
。那么这个问题实际上适用于标准。
A constexpr specifier used in an object declaration declares the object as const.
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
没有 inline
说明符,is_integral_v
将具有内部链接。如果您比较两个指向不同翻译单元中相同变量名的指针,这可能会出现问题。
注意事项:仅当变量是 class 静态数据成员时,内联说明符才与 constexpr 冗余。
下面是一个很容易违反 one definition rule 的例子,如果 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()
的定义里面,使用了ODR变量bad_is_integral_v
,所以g()
的两个定义不一样,违反了一个定义的规则。
[basic.link]/3.2 适用于 "a non-inline variable of non-volatile const-qualified type" 的名称。变量模板不是变量,就像 class 模板不是 class、函数模板不是函数、千篇一律不是曲奇饼一样。因此该规则不适用于变量模板 is_integral_v
本身。
变量模板 specialization 是一个变量,但是,因此对于该规则是否为其提供内部链接存在一些疑问。这是core issue 1713,方向是规则不适用
然而,核心问题 1713 没有及时解决 C++17。所以 LWG 决定简单地在所有变量模板上涂抹 inline
以确保安全,因为它们也不会造成伤害。