簡體   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