0

私のコードベースにはいくつかの「リソース」があります。それらはすべてクラスであり、1 つのクラスを除いて同じインターフェイスを共有します。ShaderProgram は 1 つの点で異なります。頂点ファイルとフラグメント ファイルのファイル名には 2 つの文字列が必要です。

シェーダー 1 を除くこれらすべてのリソースを処理する ResourceManager というテンプレート クラスがあります。シェーダーには 2 つのファイルが必要で、他のリソースには 1 つのファイルが必要なためです。テンプレートの特殊化でこれを解決できますか? ResourceManager が GetOrLoadFromFile( string, string ) を認識し、(string) バージョンを認識しないようにする必要がありますが、他のバージョンは逆で、(string) を認識し、(string, string) を認識しません。また、 AttemptLoad にも処理が必要です。これを解決するにはどうすればよいですか。コードを含めてください。テンプレートの特殊化はこれまで行ったことがありません。

template < class ResType > class ResourceManager
{
public:
    ResourceManager(void);
    ~ResourceManager(void);

    SmartPointer<ResType> GetOrLoadFromFile( const std::string & fileName );

    //weak_ptr<ResType> GetResourceFromID( ResourceID & resID );

    void DestroyResources();
    void ReleaseResources();
    void ReloadResources();
protected:


private:
    SmartPointer<ResType> AttemptLoad( const std::string & fileName );

    std::unordered_map<string, SmartPointer<ResType> > mResMap;

};

// Relevant methods ( SNIPPED )
template < class ResType> SmartPointer<ResType>   ResourceManager<ResType>::GetOrLoadFromFile( const std::string & fileName )
    {
    if ( !mResMap.empty() )
        {
        auto index = mResMap.begin();
        auto end = mResMap.end();

        while ( index != end )
            {
            if ( index->first == fileName )
                {
                return index->second;
                }
            ++index;
            }
        }

    return AttemptLoad(fileName);
    }

template < class ResType > SmartPointer<ResType> ResourceManager<ResType>::AttemptLoad( const std::string & fileName )
    {
    SmartPointer<ResType> pRes( new ResType() );

    if ( pRes->LoadFromFile( fileName ) )
        {
        mResMap.insert( std::make_pair( fileName, pRes ) );
        return pRes;
        }
    else
        {
        LogFailure("Failed to load resource file " + fileName)
        return SmartPointer<ResType>(nullptr);
        }
    }
4

3 に答える 3

0

テンプレートの背後にある考え方は、実行時 (つまりコンパイル時) の前に型を知っているということです。これが本当なら、あなたがやろうとしているのはテンプレートを使ったオーバーロードです。したがって、コンパイル時にオーバーロードを行う、コードに適応できる汎用コードを以下に示します。

コードを 2 回書くのを避けるために、すべての一般的なメソッドは基底クラスに入れられ、分岐するものだけが派生クラスに渡されることに注意してください。

#include <memory>
#include <string>
#include <iostream>

using namespace std;

class Base
{
  // put common codes here
};

template <typename ResType>
class ResourceManager : public Base
{
public:
  unique_ptr<ResType> GetorLoad(const string &f) { cout << f << endl; return 0;}
};

// Specilizing class ResourceManager for string type
template <>
class ResourceManager<string> : public Base
{
public:
  unique_ptr<string> GetorLoad(const string &f1, const string &f2) {cout << f1 << f2 << endl; return 0;}
};

int main()
{
  ResourceManager<int> i;
  ResourceManager<string> s;

  i.GetorLoad("int");
  s.GetorLoad("string", "string");
}

PS。この例をコンパイルしてテストするには、gcc または clang++ コンパイラの '--std=c++11' フラグを使用する必要があります

于 2013-08-06T18:40:08.470 に答える