Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 这可以通过模板专门化来解决吗?如果不能,那么如何解决?_C++_Templates_Template Specialization - Fatal编程技术网

C++ 这可以通过模板专门化来解决吗?如果不能,那么如何解决?

C++ 这可以通过模板专门化来解决吗?如果不能,那么如何解决?,c++,templates,template-specialization,C++,Templates,Template Specialization,我的代码库中有几个“资源”。它们都是类,除了一个类之外,共享同一个接口,着色器程序只有一个方面不同,它需要两个字符串作为顶点和片段文件的文件名 我有一个名为ResourceManager的模板类,它处理除着色器一个之外的所有这些资源,因为它需要两个文件,其他需要一个,我可以用模板专门化来解决这个问题吗?ResourceManager需要看到GetOrLoadFromFile(string,string)和not(string)版本,而其他版本则相反,它们看到(string)和not(string

我的代码库中有几个“资源”。它们都是类,除了一个类之外,共享同一个接口,着色器程序只有一个方面不同,它需要两个字符串作为顶点和片段文件的文件名

我有一个名为ResourceManager的模板类,它处理除着色器一个之外的所有这些资源,因为它需要两个文件,其他需要一个,我可以用模板专门化来解决这个问题吗?ResourceManager需要看到GetOrLoadFromFile(string,string)和not(string)版本,而其他版本则相反,它们看到(string)和not(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);
        }
    }
templateclass-ResourceManager
{
公众:
资源经理(作废);
~ResourceManager(无效);
智能指针GetOrLoadFromFile(const std::string和fileName);
//弱\u ptr GetResourceFromID(ResourceID和resID);
无效资源();
无效释放资源();
void重载资源();
受保护的:
私人:
SmartPointer尝试加载(const std::string和fileName);
std::无序地图mResMap;
};
//相关方法(截取)
模板SmartPointer资源管理器::GetOrLoadFromFile(const std::string和fileName)
{
如果(!mResMap.empty())
{
自动索引=mResMap.begin();
自动结束=mResMap.end();
while(索引!=结束)
{
如果(索引->第一个==文件名)
{
返回索引->秒;
}
++指数;
}
}
返回AttemptLoad(文件名);
}
模板SmartPointer ResourceManager::AttemptLoad(常量std::字符串和文件名)
{
智能指针pRes(新的ResType());
如果(pRes->LoadFromFile(文件名))
{
mResMap.insert(std::make_pair(fileName,pRes));
返回压力;
}
其他的
{
LogFailure(“加载资源文件失败”+文件名)
返回智能指针(nullptr);
}
}

如果这两个类都在您的控制之下,我会建议一个不同的解决方案。为什么不将AttempLoad方法更改为

SmartPointer<ResType> AttemptLoad( const LoadConfiguration &p_loadConfiguration );


然后,您可以始终使用LoadConfiguration,并且每个AttemptLoad都可以获取他需要的内容。添加新参数将很容易,使用相同签名的代码更少,并且您不必使用模板专门化

只需实现两个“GetOrLoadFromFile”函数:

#include <string>

struct R1 
{
  void load (const std::string &name) {}
};

struct R2 
{
  void load (const std::string &name0, const std::string name1) {}
};

template<typename R>
struct M
{
  R *get_or_load (const std::string &name)
  {
    R *p = new R();
    p->load (name);
    return p;
  }

  R *get_or_load (const std::string &name0, 
                  const std::string &name1)
  {
    R *p = new R();
    p->load (name0, name1);
    return p;
  }
};


M<R1> m1;

M<R2> m2;


int
main ()
{
  R1 *p0 = m1.get_or_load ("foo");
  // R1 *p1 = m2.get_or_load ("foo"); // error
  R2 *q0 = m2.get_or_load ("foo", "bar");
  // R2 *q1 = m1.get_or_load ("foo", "bar");  // error
}
#包括
结构R1
{
无效加载(const std::string&name){}
};
结构R2
{
无效加载(const std::string&name0,const std::string name1){}
};
模板
结构M
{
R*获取或加载(const std::string和name)
{
R*p=新的R();
p->load(名称);
返回p;
}
R*获取或加载(const std::string&name0,
常量标准::字符串和名称1)
{
R*p=新的R();
p->load(名称0,名称1);
返回p;
}
};
m1;
平方米;
int
主要()
{
R1*p0=m1.get_或_载荷(“foo”);
//R1*p1=m2.get_或_load(“foo”);//错误
R2*q0=m2.get_或_荷载(“foo”、“bar”);
//R2*q1=m1.get_或_load(“foo”,“bar”);//错误
}

“错误”的成员函数不会被实例化,除非实际上有对它的调用,在这种情况下,编译器将通过诊断退出。

模板背后的思想是,在执行之前,即编译时,您知道自己的类型。如果这是真的,那么您要做的就是使用模板进行重载。所以,下面我只放了一个通用代码,您可以适应您的代码,在编译时执行重载

请注意,为了避免编写两次代码,每个常用方法都放在基类中,并且只允许派生类使用发散的方法

#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");
}
#包括
#包括
#包括
使用名称空间std;
阶级基础
{
//把通用代码放在这里
};
模板
类资源管理器:公共基
{
公众:

uniqueptrgetorload(const string&f){cout这难道不能调用ResourceManager::AttempLoad(const LoadConfiguration)哪一个是单字符串类?在您的示例中没有任何东西可以阻止这种情况。其想法是让AttempLoad尝试对正确的LoadConfiguration类型执行动态转换。是的,从某种意义上说,您正在从编译时检查转向运行时检查。但从另一种意义上说,传递LoadConfiguration而不是ExtendedLoadConfiguration应该像传递一个空的第二个字符串一样处理—可能,并且应该易于处理。我认为标准和可扩展API的好处和舒适性比这个问题更大。
#include <string>

struct R1 
{
  void load (const std::string &name) {}
};

struct R2 
{
  void load (const std::string &name0, const std::string name1) {}
};

template<typename R>
struct M
{
  R *get_or_load (const std::string &name)
  {
    R *p = new R();
    p->load (name);
    return p;
  }

  R *get_or_load (const std::string &name0, 
                  const std::string &name1)
  {
    R *p = new R();
    p->load (name0, name1);
    return p;
  }
};


M<R1> m1;

M<R2> m2;


int
main ()
{
  R1 *p0 = m1.get_or_load ("foo");
  // R1 *p1 = m2.get_or_load ("foo"); // error
  R2 *q0 = m2.get_or_load ("foo", "bar");
  // R2 *q1 = m1.get_or_load ("foo", "bar");  // error
}
#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");
}