0

一部のコードを VC9 から G++ に移植しようとしていますが、テンプレートの特殊化が明らかにクラス メンバーに対して許可されていないという問題に遭遇しました。

次のコードは、クラス メソッドの getValue 特殊化に関するこれらのエラーの例です。すべての場合において、エラーは「エラー: 名前空間以外のスコープでの明示的な特殊化class ...」です

template<typename T> T getValue(const_iterator key)const
{
    try{return boost::lexical_cast<T>(key->second);}
    catch(boost::bad_lexical_cast &e)
    {
        throw TypeParseError<T>(name, key->first, e.what());
    }
}
template<typename T> T getValue(const std::string &key)const
{
    iterator i = find(key);
    if(i == end())throw KeyNotFound(name,key);
    else return getValue(i);
}
template<> std::string getValue<std::string>(const_iterator key)const
{
    return key->second;
}
template<> std::string getValue<std::string>(const std::string &key)const
{
    const_iterator i = find(key);
    if(i == end())throw KeyNotFound(name,key);
    else return i->second;
}

正確な構文がサポートされていないだけで、マイナーな変更で機能するのでしょうか、それともこのような特殊化を避けるためにコードを変更する必要がありますか? 後者の場合、一般的にこれを行うための最良の方法はどれですか?

4

2 に答える 2

7

これらの関数宣言を囲むクラス定義を示していません。しかし、これらのテンプレートが宣言されているクラスだと思います。外部で特殊化を定義する必要があります。

struct SomeClass {
   template<typename T> T getValue(const_iterator key)const
    {
        try{return boost::lexical_cast<T>(key->second);}
        catch(boost::bad_lexical_cast &e)
        {
            throw TypeParseError<T>(name, key->first, e.what());
        }
    }
    template<typename T> T getValue(const std::string &key)const
    {
        iterator i = find(key);
        if(i == end())throw KeyNotFound(name,key);
        else return getValue(i);
    }
};

template<> inline std::string SomeClass::getValue<std::string>(const_iterator key)const {
    return key->second;
}

template<> inline std::string SomeClass::getValue<std::string>(const std::string &key)const {
    const_iterator i = find(key);
    if(i == end())throw KeyNotFound(name,key);
    else return i->second;
}

それらを外部で定義したため、暗黙的にインライン化されていないことに注意してください。したがって、明示的にインライン化するか、cpp(ヘッダーではなく) ファイルに移動し、次のようにヘッダーで特殊化を前方宣言する必要があります。

template<> inline std::string SomeClass::getValue<std::string>(const_iterator key)const;
template<> inline std::string SomeClass::getValue<std::string>(const std::string &key)const;

前方宣言を省略した場合、コンパイラは、関数をインスタンス化するか、明示的な特殊化を使用するかを知る方法がありません。前方宣言はそれを伝えます。

于 2009-12-09T17:09:39.600 に答える
3

MSVCでは、クラススコープでの明示的な特殊化が許可されていますが、標準では許可されていません。

私が見ることができることから、あなたが与えているコードはクラス定義から来ています。クラスの範囲外に特化します。

template<> inline std::string Foo::getValue<std::string>(const_iterator key)const {
    return key->second;
}

template<> inline std::string Foo::getValue<std::string>(const std::string &key)const {
    const_iterator i = find(key);
    if(i == end())throw KeyNotFound(name,key);
    else return i->second;
}

見る:

14.7.3.2:

明示的な特殊化は、テンプレートがメンバーである名前空間で宣言する必要があります。メンバーテンプレートの場合は、包含クラスまたは包含クラステンプレートがメンバーである名前空間で宣言する必要があります。クラステンプレートのメンバー関数、メンバークラス、または静的データメンバーの明示的な特殊化は、クラステンプレートがメンバーである名前空間で宣言する必要があります。

于 2009-12-09T17:11:25.797 に答える