10

メンバー テンプレート関数を持つクラスがあります。

// writer.h
class Writer {
public:
    ...
    template <typename T, typename V>
    void addField(const std::string& name, V v) 
    {
        // write something
    }
};

そして、Writer のソース ファイルに、次の明示的な特殊化を追加しましたsome_type

// writer.cpp
template <>
void Writer::addField<some_type, int>(const std::string& name, int v)
{
    // specific some_type writing logic
}

これは機能します...時々。正しいタイプであることを確実に確認したとしても:

writer.addField<some_type>("name", static_cast<int>(some_value));

明示的な特殊化が呼び出されることもあれば、プライマリが呼び出されることもあります。何を与える?

4

1 に答える 1

19

ソースファイルで特殊化を宣言すると、診断が非常に難しいあらゆる種類の微妙な問題が発生する可能性があります。コンパイラは、ここでもあなたを助ける義務はありません。標準では、[temp.expl.spec]/6-7 のリメリックの助けを借りて、これを行わないことを強く推奨しています。

テンプレート、メンバー テンプレート、またはクラス テンプレートのメンバーが明示的に特殊化されている場合、その特殊化は、暗黙的なインスタンス化を発生させる特殊化の最初の使用の前に、そのような使用が発生するすべての翻訳単位で宣言する必要があります。 ; 診断は必要ありません。プログラムが明示的な特殊化の定義を提供しておらず、特殊化が暗黙的なインスタンス化を発生させるような方法で使用されているか、メンバーが仮想メンバー関数である場合、プログラムは不正な形式であり、診断は必要ありません。宣言されているが定義されていない明示的な特殊化に対して、暗黙的なインスタンス化が生成されることはありません。

関数テンプレート、クラス テンプレート、変数テンプレート、クラス テンプレートのメンバー関数 [...] などの明示的な特殊化宣言の配置は、明示的な特殊化宣言の相対的な配置に従って、プログラムが整形式であるかどうかに影響を与える可能性があります。上および下で指定された翻訳単位でのインスタンス化のポイント。専門化を記述するときは、その場所に注意してください。またはそれをコンパイルすることは、その自己犠牲を燃やすような試練になります.

一部の翻訳単位では、特殊化が最初の使用の前にたまたま宣言されている可能性がありますが、一部の翻訳単位では宣言されていません。ヘッダーで特殊化を宣言するだけで、このような問題をすべて完全に回避することをお勧めします。

// writer.h
class Writer {
public:
    ...
    template <typename T, typename V>
    void addField(const std::string& name, V v) 
    { /* ... */ }
};

// still writer.h
template <>
inline void Writer::addField<some_type, int>(const std::string& name, int v)
{ /* ... */ }

ヘッダーで宣言するだけで (インラインである必要はなくなりました)、ソースで定義することもできます。

于 2015-05-29T13:03:39.907 に答える