0

I have the following situation:

Base is a base class. T is a template that can assume any derived class of Base.

The underlying layer provide me data from Base class, that I need to convert to a specific class on the above layer (that layer where the code is written) to work on a user level.

Here is the code:

template <class T> class Access {
       std::vector<std::unique_ptr<T> getData();        
}

template <class T>
std::vector<std::unique_ptr<T> getData()
{
      /// Get data from below layer
      std::vector<std::unique_ptr<Base>> retData; 

      retData = getDataFromBelowLayer();

      /// Now I have to cast Base to T
      std::vector<std::unique_ptr<T>> retCastData;

      for (auto &item : retData)
      {
          std::unique_ptr<T> = static_cast<T>(item); <<---- NOT WORKING
          retCastData.push_back(std::move(item));    <<---- NOT WORKING
      }

      return retCastData;
}

How can I efficiently cast the vector of unique_ptr´s of Base class received to the vector of unique_ptr´s of T type as shown.

Thanks for helping.

davidhigh
  • 14,652
  • 2
  • 44
  • 75
Mendes
  • 17,489
  • 35
  • 150
  • 263

1 Answers1

5

This will do:

struct Base {};

template<typename T>
struct Derived : public Base {};


template <typename T>
std::vector<std::unique_ptr<T> > getData()
{
      //add some checking:
      static_assert(std::is_base_of<Base, T>::value, "T must be derived from Base");

      std::vector<std::unique_ptr<Base> > retData; 
      //fill it somehow

      std::vector<std::unique_ptr<T> > retCastData;

      for (auto& item : retData)
      {
          auto t = std::unique_ptr<T>(static_cast<T*>(item.release()));   //(*)
          retCastData.push_back(std::move(t));
      }

      return retCastData;
}

int main()
{
    getData<Derived<int> >();   //or some other type than "int"
}

The main thing happens in the line marked with (*). Here the unique-pointer is released and the returned raw pointer is downcasted to the derived class, and next inserted into the vector. (The core of this code is inspired by this thread, but the deleter stuff is omitted here.)

Note that the fact that Derived is a class template does not matter at all here (beside that you have to pass Derived</*some type*/> instead of Derived to getData).

Community
  • 1
  • 1
davidhigh
  • 14,652
  • 2
  • 44
  • 75
  • Is rhe `staric_assert` redundant, or overly strict? I mean the `static_cast` will error if the types are completely unrelated? – Yakk - Adam Nevraumont May 27 '15 at 02:10
  • @Yakk: good point. Yes, it is technically redundant, but of course there is still the more verbose error message. – davidhigh May 27 '15 at 02:13
  • @Yakk: ... which for me in practice is no reason to add it ... just wrote that down before the rest and it stayed there :-) – davidhigh May 27 '15 at 02:16
  • 1
    This is not exception safe. If `emplace_back` throws, the pointer that has been `release()`'d is leaked. – T.C. May 27 '15 at 02:32
  • @T.C.: thanks for the thorough inspection. I'll made an edit which I think corrects on this (as `release()` and the `unique_ptr` constructor are both `noexcept`). – davidhigh May 27 '15 at 02:44