javaLover javaLover - 8 months ago 28
C++ Question

Enforce template function to be T=B* inside a class<std::unique_ptr<B>>

I have a storage class, it can add/remove element.

Most of its public functions share a very similar signature as shown function :-

template<class T> class Storage{
public: void add(T& t){ ... }
//... other fields,functions

A great thing is that
can be value or raw pointer.

Now I want to upgrade this storage to support

This is what I want to accomplish:-

Storage<std::unique_ptr<B>> store;
B* b = new B();
store.add(b); //my attempt - it is currently not supported

Here is my draft to support the new feature:-

template<class T> class Storage{
public: template<class TWeak> void add(TWeak& tw){ ... }
//... other fields,functions

From the draft, I think it is somewhat dangerous to use
as a template argument -
can be anything.

It is contradict to my intention that
can only be
T's weakpointer
, roughly speaking.

More specifically, I want to enforce this rule :-

When T=std::unique_ptr<B> ==> TWeak have to be B* or std::unique_ptr<B>
When T=B* ==> TWeak have to be B*
When T=B ==> TWeak have to be B

How to enforce the rules elegantly?

A solution that has 2
functions is still acceptable.


To keep the interface simple, you can extend the Storage with a specialization, which serves enclosing types like unique_ptr:

template<class T>
class Storage<std::unique_ptr<T>> : public Storage<T*>{
  public: using Storage<T*>::add;
  public: void add(std::unique_ptr<T>& t){ ... }  // 

We inherit, Storage<T*> because:

  1. T* goes well with unique_ptr<T> as per a requirement in your question
  2. It includes all the common methods. The special methods like add() are defined separately and using directive is used to unhide the base methods


Storage<int> si; si.add(/*int variable*/);
Storage<int*> spi; spi.add(/*int* variable*/);
Storage<std::unique_ptr<int>> su; su.add(/*int* or unique_ptr<int> variable*/);

Here is a demo.