2017-02-14 6 views
1

静的(constexpr)メンバのリンケージについては、多くの回答があります。静的constexprメンバを持つテンプレートクラスのODR

しかし、テンプレートクラスのアウトオブライン定義をヘッダファイルで使用するのはなぜですか?特殊なクラスでは機能しません。

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の定義を緩和すると便利でしょうか?

ありがとうございます!

+1

「*将来的には、Bのようなそのような場合のためのODRの定義を緩和することは有用であろう*?」すでにC++ 17で:constexprの静的データメンバーは暗黙的に 'インライン'です。 – ildjarn

+0

素敵!それを待つことはできません。 :) – Viatorus

答えて

3

参照[basic.def.odr]/6:

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<typename T> 
constexpr std::array<int, 1> Foobar<int, T>::a; 

を持っています複数定義することができます。第二のスニペットでは、あなたはテンプレート宣言ない

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

を持っている:定義自体が定義されているものは、テンプレートの専門であることを起こるにもかかわらず、テンプレート化されていません。

My question to you:

  1. Is it save to use the template trick? What are the disadvantage?

「トリック」はありません。のメンバーをすべてFoo<T>と定義する場合は、定義をヘッダーファイルに入れるだけです。 のメンバをFoo<T>のようにFoo<int>のように定義したい場合は、インライン変数を導入するC++ 17までの定義をヘッダーファイルに入れてはいけません。あなたが想定しているのでトリックはありませんあなたの特定の目標に依存します。

(あなたの2番目の質問は、コメント欄に答えた。)

関連する問題