具有静态constexpr成员的模板类的ODR [英] ODR of template class with static constexpr member

查看:123
本文介绍了具有静态constexpr成员的模板类的ODR的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道,关于静态(constexpr)成员的链接,有很多已回答的问题.

I know, there are many answered question about linkage of a static (constexpr) members.

但是我想知道,为什么使用模板类的脱机定义可以在头文件中使用而不能用于专门的类.

But I wonder, why using a template class out-of-line definition works in a header file but not for a specialized class.

a)这可以正常工作而不会出现链接器错误:

a) This works without linker error:

template<typename, typename>
struct Foobar;

template<typename T>
struct Foobar<int, T> {
  static constexpr std::array<int, 1> a = {{1}};
};

template<typename T>
constexpr std::array<int, 1> Foobar<int, T>::a;

// foo.cpp
std::cout << Foobar<int, int>::a[0] << "\n";

// bar.cpp
std::cout << Foobar<int, int>::a[0] << "\n";

的objdump:

foo.o:0000000000000000 w O .rodata._Z6FoobarIiiE1aE 0000000000000004 _Z6FoobarIiiE1aE

bar.o:0000000000000000 w O .rodata._Z6FoobarIiiE1aE 0000000000000004 _Z6FoobarIiiE1aE

链接文件:0000000000475a30 w O .rodata 0000000000000004 _Z6FoobarIiiE1aE

b)这不是(多个定义):

b) This does not (multiple definition):

template<typename>
struct Foobar;

template<>
struct Foobar<int> {
  static constexpr std::array<int, 1> a = {{1}};
};
constexpr std::array<int, 1> Foobar<int>::a;

// foo.cpp
std::cout << Foobar<int>::a[0] << "\n";

// bar.cpp
std::cout << Foobar<int>::a[0] << "\n";

的objdump:

foo.o 0000000000000100 g O .rodata 0000000000000004 _Z6FoobarIiE1aE

bar.o:0000000000000420 g O .rodata 0000000000000004 _Z6FoobarIiE1aE

我们看到的是,离线定义在目标文件中具有不同的地址(示例b)).

What we see, the out-of-line definition has different addresses inside the object files (example b)).

我对你的问题

  1. 使用模板技巧是否保存?缺点是什么?
  2. 将来在类似b的情况下放宽odr的定义是否有用?

提前谢谢!

推荐答案

请参阅[basic.def.odr]/6:

See [basic.def.odr]/6:

一个类类型(第9条),枚举类型(7.2),具有以下内容的内联函数可以有多个定义: 外部链接(7.1.2),类模板(条款14),非静态功能模板(14.5.6),静态数据成员 类模板(14.5.1.3),类模板的成员函数(14.5.1.1)或模板专用化 程序中未指定哪些模板参数(14.7、14.5.5),前提是每个定义 出现在不同的翻译单元中,并且提供的定义满足以下要求. ...

There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. ...

此规则的作用是每个 template-declaration 的行为都像是内联的. (但它不扩展到 explicit-instantiation explicit-specialization 声明.)

The effect of this rule is that every template-declaration behaves as though it is inline. (But it does not extend to explicit-instantiation and explicit-specialization declarations.)

在第一个代码段中,您有

In the first snippet, you have

template<typename T>
constexpr std::array<int, 1> Foobar<int, T>::a;

template-declaration (模板声明),因此可以被多重定义.在第二个片段中,您有

which is a template-declaration and therefore is allowed to be multiply defined. In the second snippet, you have

constexpr std::array<int, 1> Foobar<int>::a;

这不是 template-declaration :即使定义的对象碰巧是模板的特殊化,定义本身也不是模板化的.

which is not a template-declaration: the definition itself is not templated, even though the thing being defined happens to be a specialization of a template.

我对你的问题

My question to you:

  1. 使用模板技巧是否保存?缺点是什么?

这里没有把戏".如果要为 all Foo<T>定义成员,则别无选择,只能将定义放入头文件中.如果要为一个特定的 Foo<T>(例如Foo<int>)定义成员,则不得将定义放在头文件中(直到C ++ 17,它引入了内联变量.)没有窍门,因为您应该做什么取决于您的特定目标.

There is no "trick" here. If you want to define the member for all Foo<T>, then you have no choice but to put the definition in the header file. If you want to define the member for one specific Foo<T> such as Foo<int>, then you must not put the definition in the header file (until C++17, which introduces inline variables.) There is no trick because what you are supposed to do depends on your specific goal.

(在评论部分回答了您的第二个问题.)

(Your second question was answered in the comment section.)

这篇关于具有静态constexpr成员的模板类的ODR的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆