タイプではないテンプレートパラメータ


93

型ではないテンプレートパラメータは定数積分式でなければならないことを理解しています。誰かが光を当てることができるのはなぜですか?

template <std::string temp>
void foo()
{
     // ...
}
error C2993: 'std::string' : illegal type for non-type template parameter 'temp'.

定数積分式とは何かを理解しています。std::string上記のスニペットのように非定数型を許可しない理由は何ですか?


17
テンプレートパラメータはコンパイル時に解決されます。
エティエンヌデマルテル

回答:


121

これを実行できないのは、コンパイル時に非定数式を解析および置換できないためです。テンプレートは実行時に変更される可能性があり、実行時に新しいテンプレートを生成する必要があります。テンプレートはコンパイル時の概念であるため、これは不可能です。

標準でタイプ以外のテンプレートパラメータに許可されているものを次に示します(14.1 [temp.param] p4)。

タイプではないテンプレートパラメータは、次の(オプションでcv修飾された)タイプのいずれかを持つ必要があります。

  • 整数型または列挙型
  • オブジェクトへのポインタまたは関数へのポインタ
  • オブジェクトへの左辺値参照または関数への左辺値参照
  • メンバーへのポインター
  • std::nullptr_t

6
@ALOToverflow:それは「メンバーへのポインター」に該当します。「メンバー関数へのポインター」または「メンバーデータへのポインター」のいずれかです。
Xeo

4
オブジェクト(またはインスタンスフィールド)へのポインターの場合、オブジェクトは静的な保存期間とリンケージ(外部C ++ 11以前、C ++ 11では内部または外部)を持つ必要があるため、それらへのポインターはコンパイル時に作成されます。
セオドアマードック2016年

2
C ++ 20では、型が強力な構造化された等価性を持ち、リテラルであり、変更可能/揮発性のサブオブジェクトがなく、宇宙船演算子がパブリックである場合に、これが許可されます。
Rakete1111

73

それは許されない。

ただし、これは許可されています。

template <std::string * temp> //pointer to object
void f();

template <std::string & temp> //reference to object
void g();

C ++ Standard(2003)の§14.1/ 6,7,8を参照してください。


図:

template <std::string * temp> //pointer to object
void f()
{
   cout << *temp << endl;
}

template <std::string & temp> //reference to object
void g()
{
     cout << temp << endl;
     temp += "...appended some string";
}

std::string s; //must not be local as it must have external linkage!

int main() {
        s = "can assign values locally";
        f<&s>();
        g<s>();
        cout << s << endl;
        return 0;
}

出力:

can assign values locally
can assign values locally
can assign values locally...appended some string

7
@Mahesh:テンプレートが基本的にテンプレート化するのは、そのstd::stringポインターまたは参照オブジェクトのアドレスだからです。その変数がローカルである場合、関数が呼び出されるたびに異なるアドレスを取得する可能性があります。
Xeo 2011

11
@Mahesh:コンパイル時にコールスタックがどのように見えるかわかりません。関数の前に、他に10個、他に3個、またはその他多くのものが呼び出されている可能性があるため、文字列が作成されるスタック上のアドレスは呼び出しごとに変わる可能性があります。外部リンケージのあるオブジェクトがある場合、そのアドレスはコンパイル/リンケージ中に固定されます。
Xeo 2011

2
@Xeo " そのアドレスはコンパイル/リンケージ中に固定されます。 "またはそうではなく、再配置可能または位置に依存しないコードの場合。
curiousguy 2013年

1
この回答(現在のところ)はこの動作が存在する理由を尋ねているOPの質問に対応していないようです。この回答は、OPの例を説明し直すことなく、単に説明しているだけです。
Quuxplusone 2017

1
パーティーに遅れました、スマートポインターも機能しないようです
ニコラスハンフリー

28

テンプレート引数をマングルできる必要があります

template <std::string temp>
void f() {
 // ...
}

f<"foo">();
f<"bar">(); // different function!?

これで、実装は固有の文字のシーケンスを考え出す必要があります std::string実装は、特定の値を格納する特定の値を格納する、またはさらに言えば他の任意のユーザー定義クラスのますが、その意味は実装には不明です。さらに、コンパイル時に任意のクラスオブジェクトの値を計算することはできません。

定数式で初期化されるポストC ++ 0xのテンプレートパラメータタイプとして、リテラルクラスタイプを許可することを検討する予定です。これらの値は、データメンバーをその値に従って再帰的にマングルすることでマングルできます(たとえば、基本クラスの場合、深さ優先、左から右へのトラバーサルを適用できます)。しかし、任意のクラスでは確実に機能しません。


10

テンプレート引数リスト内で提供される非タイプのテンプレート引数は、コンパイル時に値を決定できる式です。このような引数は次のとおりです。

定数式、外部リンケージを持つ関数またはオブジェクトのアドレス、または静的クラスメンバーのアドレス。

また、文字列リテラルは内部リンケージを持つオブジェクトであるため、テンプレート引数として使用することはできません。また、グローバルポインターも使用できません。丸め誤差の明らかな可能性があるため、浮動小数点リテラルは許可されません。


引用を使用したので、ソースは何ですか?それが引用のソースがある場合、私はそれを賛成したいと思います。
ガブリエルステープルズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.