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;
};
The problem here is that
is not valid syntax in C++. If you want to constrain
T
to be aRepositoryBase
or derived fromRepositoryBase
then you need to do that in thetemplate<typename T>
part. What we do is add a check of the type thatT
is and if that check fails the then compiler will not generate the function which will cause a compiler error. That would looks like