【问题标题】:C++ object factory with built-in cache - shadows template parameter具有内置缓存的 C++ 对象工厂 - 阴影模板参数
【发布时间】:2018-02-03 16:23:26
【问题描述】:

我有一个数据库类,它应该提供一个模板方法来返回代表表的存储库对象。每个存储库应仅存在一次。我找到了this 示例,但我想要一个内置缓存。

database.h 标头如下所示:

class Database
{
public:
  Database(const char *connectionString);
  template<typename T> shared_ptr<class T : RepositoryBase> GetRepository();

private:
  sqlite3* _connection;
  map<string, RepositoryBase> _repositoryCache;
};

GetRepository 方法的实现如下:

template<typename T> shared_ptr<class T : RepositoryBase> Database::GetRepository()
{
  string name = typeid(T).name();

  if(_repositoryCache.count(name) == 0)
  {
    _repositoryCache[name] = shared_ptr<T>(new T(_connection));
  }

  return _repositoryCache[name];
}

我想这样称呼它:

// SampleRepository is derived from RepositoryBase
shared_ptr<SampleRepository> sampleRepo = GetRepository<SampleRepository>();

编译时出现错误:

error : declaration of 'T' shadows template parameter

我需要在模板方法中更改什么以不隐藏任何模板参数?


更新

根据 NathanOliver 的建议,模板方法如下所示:

template<typename T, typename enable_if<is_base_of<RepositoryBase, T>::value>::type* = nullptr> shared_ptr<T> Database::GetRepository()
{
  string name = typeid(T).name();

  if(_repositoryCache.count(name) == 0)
  {
    _repositoryCache[name] = shared_ptr<T>(new T(_connection));
  }

  return _repositoryCache[name]();
}

这次我得到了错误:

error : template parameter redefines default argument

它指向模板签名中的nullptr


更新 2

根据@NathanOliver 给出的答案,我尝试了几种参数组合。我仍然收到错误:

1>C:\..\Database.cpp(65,98): error : template parameter redefines default argument
1>template<typename T, typename std::enable_if<std::is_base_of<RepositoryBase, T>::value>::type* = nullptr> std::shared_ptr<T> Database::GetRepository()
1>                                                                                                 ^
1>C:\..\Database.h(25,108) :  note: previous default template argument defined here
1>          template<typename T, typename std::enable_if<std::is_base_of<RepositoryBase, T>::value>::type* = nullptr> std::shared_ptr<T> GetRepository();
1>                                                                                                           ^

为了更好地理解,我还添加了存储库基类。

class RepositoryBase
{
public:
  RepositoryBase(sqlite3* connection);
  virtual string GetTableName() = 0;

  protected:
    sqlite3* _connection;
 };

【问题讨论】:

  • Database 模板化了吗?如果是这样,template&lt;stuff&gt; 部分是什么样的?
  • 没有。您可以在数据库头文件中看到只有GetRepository 模板化的函数。
  • 你想用shared_ptr&lt;class T : RepositoryBase&gt;做什么?你是想说T 需要从RepositoryBase 派生吗?
  • shared_ptr&lt;class T : RepositoryBase&gt; 看起来像 Java 的泛型。这不是 C++,因此出现错误。
  • + 小心使用map&lt;string, RepositoryBase&gt; 进行切片。

标签: c++ objectfactory


【解决方案1】:

这里的问题是

template<typename T> shared_ptr<class T : RepositoryBase> GetRepository();

在 C++ 中不是有效的语法。如果您想将T 限制为RepositoryBase 或派生自RepositoryBase,那么您需要在template&lt;typename T&gt; 部分中执行此操作。我们所做的是添加对T 类型的检查,如果检查失败,则编译器将不会生成将导致编译器错误的函数。看起来像

template<typename T, typename std::enable_if<std::is_base_of<RepositoryBase, T>::value>::type* = nullptr> 
shared_ptr<T> GetRepository();

【讨论】:

  • 感谢您的回复。对我来说,它看起来是我想要的。我收到以下错误:error : template parameter redefines default argument,它在模板签名中指向nullptr。实现是否需要在定义的标头中看起来不同?
  • @BrunoBieri 应该是这样的:coliru.stacked-crooked.com/a/6ba2e0bad6e9f968
  • 感谢您的示例代码!我还是想不通。我收到错误error : template parameter redefines default argument。任何提示这可能导致什么?
  • 据我了解,clang 不允许有标题和我在这里学到的实现:stackoverflow.com/a/14197544/1306012
  • @brunobieri 看起来您在头文件和 CPP 文件之间拆分模板代码。你不能那样做。
猜你喜欢
  • 2023-04-03
  • 2011-09-30
  • 1970-01-01
  • 1970-01-01
  • 2016-06-15
  • 1970-01-01
  • 1970-01-01
  • 2011-03-22
  • 2018-05-02
相关资源
最近更新 更多