C++ object factory with built-in cache - shadows template parameter

555 views Asked by At

I've a database class which should provide a template method to return repository objects representing tables. Each repository shall exist only once. I found this example but I want to have an built-in cache.

The database.h header looks like this:

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

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

The implementation the GetRepository method looks like:

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];
}

I would like to call it like that:

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

When I compile I get the error:

error : declaration of 'T' shadows template parameter

What do I need to change in the template method to not shadowing any template parameter?


UPDATE

After NathanOliver's suggestions the template method looks like:

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]();
}

This time I get the error:

error : template parameter redefines default argument

It points to nullptr in the template signature.


UPDATE 2

I've tried several combinations of the parameters based on the answer given from @NathanOliver. Still I get the error:

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>                                                                                                           ^

For a better understanding I've added the repository base class as well.

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

  protected:
    sqlite3* _connection;
 };
1

There are 1 answers

5
NathanOliver On BEST ANSWER

The problem here is that

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

is not valid syntax in C++. If you want to constrain T to be a RepositoryBase or derived from RepositoryBase then you need to do that in the template<typename T> part. What we do is add a check of the type that T is and if that check fails the then compiler will not generate the function which will cause a compiler error. That would looks like

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