web-dev-qa-db-ja.com

インスタンス化エラー後のメンバー関数テンプレートの特殊化、およびメンバー関数の順序

次のコードは、gcc 4.5.3でコンパイルできません。

_struct Frobnigator
{
    template<typename T>
    void foo();

    template<typename T>
    void bar(); 
};

template<typename T>
void Frobnigator::bar()
{
}

template<typename T>
void Frobnigator::foo()
{
    bar<T>();
}

template<>      // error
void Frobnigator::foo<bool>()
{
    bar<bool>();
}

template<>
void Frobnigator::bar<bool>()
{
}

int main()
{
}
_

エラーメッセージ:specialization of ‘void Frobnigator::bar() [with T = bool]’ after instantiationFrobnigator::bar<bool>()の特殊化をFrobnigator::foo<bool>()の前に置くことで、この問題を最後に解決しました。明らかに、メソッドが現れる順序は重要です。

それでは、上記のコードの次のライトバージョンがなぜ一般的なバージョンの後にbarの特殊化が現れるのですか?

_struct Frobnigator
{
    template<typename T>
    void foo();
};

template<typename T>
void Frobnigator::bar()
{
}

template<>
void Frobnigator::bar<bool>()
{
}

int main()
{
}
_
18
Olumide

最初のコードは標準では正しくありません。

n3376 14.7.3/6

テンプレート、メンバーテンプレート、またはクラステンプレートのメンバーが明示的に特殊化されている場合、その特殊化は、暗黙的なインスタンス化が行われるその特殊化の最初の使用の前に宣言されます、すべての変換でそのような使用が発生するユニット。診断は必要ありません。

あなたの場合-明示的な特殊化宣言の前に、foo<bool>での使用には、タイプbarbool関数の暗黙的なインスタンス化が必要です。

28
ForEveR

明らかに、メソッドが現れる順序は重要です。

確かに; C++で通常そうであるように、宣言する前に何かを使用することはできません。これは、明示的なテンプレートの特殊化だけでなく、他のほとんどのものに適用されます。

明示的な特殊化を事前に宣言せずにbar<bool>を(foo<bool>から呼び出すことにより)使用すると、その特殊化は汎用テンプレートからインスタンス化されます(まだ作成されていない場合)。それを防ぐには、少なくとも明示的な特殊化の宣言が必要です。

上記のコードの次のライトバージョンでジェネリックバージョンの後にbarの特殊化が表示されることを考えると、これはなぜですか

2番目の例は、foo<bool>をまったくインスタンス化しない点が異なります。問題は、特殊化が汎用テンプレートの後に宣言されていること(そうである必要があります)ではなく、その特殊化が既にインスタンス化されている後に宣言されていることです。

3
Mike Seymour