12

C++11 標準 N3485 セクション 14.1.7 の次の段落を理解するのに問題があります。事実を暗記するよりも、理論的根拠を理解することが重要だと思います。

非型テンプレート パラメータは、浮動小数点、クラス、または void 型を持つように宣言してはなりません。
[ 例:

template<double d> class X; // error
template<double* pd> class Y; // OK
template<double& rd> class Z; // OK

—終わりの例]

この規則に関していくつか質問があります。

  1. floating pointtype をテンプレート パラメーターとして使用できない理由はありますか? その背後にある理論的根拠は何ですか?これは C++11 より前に当てはまることを知っており、C++11 標準にも当てはまるようです。

  2. pointerまたはreference浮動小数点型を非テンプレート パラメータとして使用しても問題ないのに、生の浮動小数点型ではないのはなぜですか? ここでの大きな違いは何ですか?

ご協力ありがとうございました。

4

2 に答える 2

8

浮動小数点型をテンプレート パラメータとして使用できない理由はありますか? その背後にある理論的根拠は何ですか?

究極の理由を示すことはできませんが、浮動ポインター値をパラメーターとして受け入れるテンプレートを特殊化すると問題が発生することは間違いなく想像できます。

浮動小数点数間の等値比較は注意が必要であり (予期しない結果が生じる場合があるという意味で)、特殊化を照合する場合、コンパイラは提供された引数とテンプレートが特殊化されている値との間で等値チェックを実行する必要があります。

もう 1 つの同様の問題は、同じクラス テンプレートの 2 つのインスタンスが実際に同じ型であるかどうかを判断することです。

template<double D>
struct X
{
    // ...
};

int main()
{
    X<3.0> x;
    X<some_constant_expression()> y;
}

xyインスタンスは同じクラスですか? これを判断するには、 と の間で等価性チェックを実行する必要が3.0ありsome_constant_expression()ます。

浮動小数点型へのポインタまたは参照を非テンプレート パラメータとして使用しても問題ないのに、生の浮動小数点型では問題ないのはなぜですか?

上記のシナリオに関して、ポインターに関する答えは簡単です。ポインターは整数値であり、ポインター間の比較は明確に定義されています。

参照に関しては、それらが実際にはポインターのように扱われることを示す証拠があります。

#include <type_traits>

double a = 0.0;
double b = 0.0;

template<double& D>
struct X : std::false_type { };

template<>
struct X<a> : std::true_type { }

int main()
{
    static_assert(X<a>::value, "!"); // Does not fire
    static_assert(X<b>::value, "!"); // Fires
}

また、C++11 標準のパラグラフ 14.4/1 ごとに:

2 つのテンプレート IDが同じクラスまたは関数を参照している場合

— [...]

— 対応する整数型または列挙型の非型テンプレート引数は、同一の値を持ち、

— [...]

— それらに対応する参照型の非型テンプレート引数は、同じ外部オブジェクトまたは関数を参照し、

— [...]

例:

template<class E, int size> class buffer { / ... / };
buffer<char,2*512> x;
buffer<char,1024> y;

xとが同じ型であることを宣言しy、[...]

上記は、同じクラス テンプレートの 2 つの異なるインスタンスが実際に同じクラスであるかどうかを判断するには、テンプレート引数として使用される定数式間の等価性チェックが必要であることを示しています。

于 2013-05-22T14:20:05.867 に答える
2

これを理解するには、整数型とポインターが常にそのリテラル表現と 1 対 1 の関係にあることを考慮してください。

しかし、非型の template を考えてみましょうFoo<float>

のような非バイナリ表現可能な数値に特化しているとしましょう0.1:Foo<0.1>そして、コンパイラーが特殊化に基づいてシンボル名を装飾しFoo_3DCCCCCC、コンパイラーがIEEE 754 32ビット表現に「切り捨て」を使用しているため、次のようなものになるとしましょう.

しかし、このコードのユーザーがコンパイルしているとしましょう。これは、コンパイラが代わりに「正の無限大への丸め」を選択するような方法です。次に、特殊化の名前は代わりFoo_3DCCCCCDに、以前に別の翻訳単位に特化されたものとはまったく異なる機能です。

これらすべての種類のもの (NaN、無限大、およびその他の非正規数はどうなるでしょうか?) を処理するためのさまざまなルールを作成し始めない限り、ミスマッチやあらゆる種類の問題が発生する可能性があります。

于 2013-05-22T14:46:21.310 に答える