Search code examples
c++c++11pointerssmart-pointersfunction-templates

is there a way to write a template function for dealing with smart pointer and regular pointer?


please i m trying to write a function that accept a vector of smart pointer or regular pointer but it never work, I want to write function getLargestRadius() that accept as argument std::vector<something*> or std::vector<std::shared_ptr<something>>. the only way it work for me is by overloading the function here is my full code to understand exactly what i mean:

#include <iostream>
#include <vector>
#include <memory>

class Point
{
private:
    int m_x{ 0 };
    int m_y{ 0 };
    int m_z{ 0 };

public:
    Point() = default;
    Point(int x, int y, int z)
        : m_x{x}, m_y{y}, m_z{z}
    {

    }

    friend std::ostream& operator<<(std::ostream &out, const Point &p)
    {
        out << "Point(" << p.m_x << ", " << p.m_y << ", " << p.m_z << ')';
        return out;
    }
};

class Shape
{
public:
    virtual std::ostream& print(std::ostream &out) const = 0;

    friend std::ostream& operator <<(std::ostream &out, const Shape &shape)
    {
        return shape.print(out);
    }
    virtual ~Shape() {}
};

class Triangle : public Shape
{
private:
    Point m_a;
    Point m_b;
    Point m_c;
public:
    Triangle(const Point &a, const Point &b, const Point &c)
        : m_a{a}, m_b{b}, m_c{c}
    {}
    virtual std::ostream& print(std::ostream &out) const override
    {
        out << "Trinagle(";
        out << m_a << ", ";
        out << m_b << ", ";
        out << m_c << ")";
        return out;
    }

};
class Circle: public Shape
{
private:
    Point m_center;
    int m_radius;

public:
    Circle(const Point &center, int radius)
        : m_center{center}, m_radius{radius}
    {
    }

    virtual std::ostream& print(std::ostream &out) const override
    {
        out << "Circle(" << m_center << ", radius " << m_radius << ')';
        return out;
    }

    int getRadius() const {return m_radius;}
};


int getLargestRadius(std::vector<std::shared_ptr<Shape>> &v)
{
    int largestRadius { 0 };

    for(int x{0}; x < static_cast<int>(v.size()); ++x)
    {
            if (dynamic_pointer_cast<Circle>(v[x]))
        {
            if (dynamic_cast<Circle&>(*v[x]).getRadius() > largestRadius)
                largestRadius = dynamic_cast<Circle&>(*v[x]).getRadius();
        }
    }

    return largestRadius;
}

int getLargestRadius(std::vector<Shape*> &v)
{
    int largestRadius { 0 };

    for(int x{0}; x < static_cast<int>(v.size()); ++x)
    {
            if (dynamic_cast<Circle*>(v[x]))
        {
            if (dynamic_cast<Circle*>(v[x])->getRadius() > largestRadius)
                largestRadius = dynamic_cast<Circle*>(v[x])->getRadius();
        }
    }

    return largestRadius;
}
int main()
{

    std::vector<std::shared_ptr<Shape>> v1 {
        std::make_shared<Circle>(Point{1, 2, 3}, 7),
        std::make_shared<Triangle>(Point{1, 2, 3}, Point{4, 5, 6}, Point{7, 8, 9}),
        std::make_shared<Circle>(Point{4, 5, 6}, 3)
    };

    std::vector<Shape*> v2{
      new Circle{Point{1, 2, 3}, 7},
      new Triangle{Point{1, 2, 3}, Point{4, 5, 6}, Point{7, 8, 9}},
      new Circle{Point{4, 5, 6}, 3}
    };

    for(auto &element : v1)
        std::cout << *element << '\n';


    std::cout << "The largest radius is: " << getLargestRadius(v1) << '\n';
    std::cout << "The largest radius is: " << getLargestRadius(v2) << '\n';

    for(auto &element : v2)
        delete element;

    return 0;
}

i tried to make it as template but nothing work. as you can see i had to overload the function to let it work with both vector type so is there a way to use template to make it only one function work with all type.

thank you


Solution

  • Without check, you might do, with template:

    template <typename T>
    int getLargestRadius(const std::vector<T>& v)
    {
        int largestRadius { 0 };
    
        for (const auto& shapePtr : v)
        {
            if (const auto* circle = dynamic_cast<const Circle*>(&*shapePtr))
            {
                largestRadius = std::max(largestRadius , circle->radius);
            }
        }
    
        return largestRadius;
    }
    

    To treat both regular and smart pointer equally, I deference them (*shapePtr) so then I have a reference.

    (then I need to got back regular pointer, so I take address &*shapePtr).