繁体   English   中英

带有静态constexpr成员的模板类的ODR

[英]ODR of template class with static constexpr member

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

但我想知道,为什么使用模板类的外部定义在头文件中工作,但不适用于专门的类。

a)这没有链接器错误:

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)这不是(多重定义):

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))。

我向你提问:

  1. 是否保存使用模板技巧? 有什么缺点?
  2. 如果将来像b这样的案例放宽odr的定义会有用吗?

先感谢您!

见[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)的模板特化,前提是每个模板定义出现在不同的翻译单元中,并且定义满足以下要求。 ...

此规则的作用是每个模板声明的行为都像是内联的。 (但它不会扩展到显式实例化 式特化声明。)

在第一个片段中,你有

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

这是一个模板声明 ,因此可以进行多重定义。 在第二个片段中,你有

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

这不是模板声明 :定义本身不是模板化的,即使被定义的东西恰好是模板的特化。

我向你提问:

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

这里没有“诡计”。 如果要为所有 Foo<T>定义成员,那么您别无选择,只能将定义放在头文件中。 如果要为一个特定的 Foo<T>定义成员,例如Foo<int> ,则不能将该定义放在头文件中(直到C ++ 17,它引入了内联变量。)没有技巧,因为你应该做什么取决于你的具体目标。

(你的第二个问题在评论部分得到了解答。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM