Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatic Return Type for Pointers in C++

I hope the headline isn't too confusing. What I have is a class StorageManager containing a list of objects of classes derived from Storage. Here is an example.

struct Storage {};                         // abstract

class StorageManager
{
private:
    map<string, unique_ptr<Storage>> List; // store all types of storage

public:
    template <typename T>
    void Add(string Name)                  // add new storage with name
    {
        List.insert(make_pair(Name, unique_ptr<Storage>(new T())));
    }

    Storage* Get(string Name)              // get storage by name
    {
        return List[Name].get();
    }
};

Say Position is a special storage type.

struct Position : public Storage
{
    int X;
    int Y;
};

Thanks to the great answers on my last question the Add function already works. What I want to improve is the Get function. It reasonable returns a pointer Storage* what I can use like the following.

int main()
{
    StorageManager Manager;
    Manager.Add<Position>("pos");    // add a new storage of type position

    auto Strge = Manager.Get("pos"); // get pointer to base class storage
    auto Pstn = (Position*)Strge;    // convert pointer to derived class position

    Pstn->X = 5;
    Pstn->Y = 42;
}

It there a way to get rid of this pointer casting by automatically returning a pointer to the derived class? Maybe using templates?

like image 804
danijar Avatar asked Jul 14 '26 05:07

danijar


1 Answers

I don't see what you can do for your Get member function besides what @BigBoss already pointed out, but you can improve your Add member to return the used storage.

template <typename T>
T* Add(string Name)                  // add new storage with name
{
   T* t = new T();
   List.insert(make_pair(Name, unique_ptr<Storage>(t)));
   return t;
}

// create the pointer directly in a unique_ptr
template <typename T>
T* Add(string Name)                  // add new storage with name
{
  std::unique_ptr<T> x{new T{}};
  T* t = x.get();
  List.insert(make_pair(Name, std::move(x)));
  return t;
}

EDIT The temporary prevents us from having to dynamic_cast. EDIT2 Implement MatthieuM's suggestion.

You can also further improve the function by accepting a value of the type to be inserted, with a default argument, but that might incur an additional copy.

like image 50
pmr Avatar answered Jul 17 '26 21:07

pmr