Reputation: 55
I am having trouble getting around this one. Let's say I have this vector
std::vector<std::shared_ptr<Car>> cars;
Car is an abstract class. I want to be able to return weak pointers of different types so I do the following.
template<typename T>
std::weak_ptr<T> GetCar()
{
for (std::vector<std::shared_ptr<Car>>::iterator it = cars.begin(); it != cars.end(); ++it)
{
T* derived = dynamic_cast<T*>((*it).get());
if (derived != nullptr)
{
std::weak_ptr<T> carPointer = *it;
return carPointer;
}
}
return std::weak_ptr<T>();
}
I get the following error though when I try to use the function with a class that inherits from Car.
Error C2440 'initializing': cannot convert from 'std::shared_ptr<Car>' to 'std::weak_ptr<Saab>'
There might not be a valid car when asked for it. I tried using boost::optional but it does not handle polymorphism . I might go with raw pointers if I can't get this to work.
Upvotes: 5
Views: 6059
Reputation: 1775
You can't construct directly your weak_ptr<Saab>
from the shared_ptr<Car>
because the template parameter Car
must implicitly be convertible to Saab
in order to work.
But you can first convert your shared_ptr<Car>
to shared_ptr<Saab>
at first then construct your weak_ptr
afterward. In my example below, I used the std::dynamic_pointer_cast
to do it.
Here is what I came up with :
#include <iostream>
#include <vector>
#include <memory>
struct Car
{
virtual void name() = 0;
};
struct Saab : Car
{
virtual void name() { std::cout << "Saab" << std::endl; }
};
struct Renault : Car
{
virtual void name() { std::cout << "Renault" << std::endl; }
};
template<typename T>
std::weak_ptr<T> GetCar(std::vector<std::shared_ptr<Car>> cars)
{
for (std::vector<std::shared_ptr<Car>>::iterator it = cars.begin(); it != cars.end(); ++it)
{
auto derived = std::dynamic_pointer_cast<T>(*it);
if (derived != nullptr)
{
std::weak_ptr<T> carPointer(derived);
return carPointer;
}
}
return std::weak_ptr<T>();
}
int main()
{
std::vector<std::shared_ptr<Car>> cars;
cars.push_back(std::make_shared<Saab>());
cars.push_back(std::make_shared<Renault>());
auto wp = GetCar<Saab>(cars);
auto sp = wp.lock();
if (sp)
{
sp->name();
}
auto wp2 = GetCar<Renault>(cars);
auto sp2 = wp2.lock();
if (sp2)
{
sp2->name();
}
}
It prints out :
Saab
Renault
Coliru link : http://coliru.stacked-crooked.com/a/9dbb85b556b83597
Upvotes: 5