【问题标题】:How to write a template function that adds an object of variant class type to a vector?如何编写将变体类类型的对象添加到向量的模板函数?
【发布时间】:2021-05-27 18:27:51
【问题描述】:

我还有一个问题,我不知道如何解决。也许有人可以帮助我。

我想做什么: 我有一个向量,它将采用各种类类型的元素。在我的示例代码中,我有两个类(Line、circle),它们都派生自一个虚拟类段。 我的代码将链接几个圆形或线条元素并将它们放入向量中。每个元素可能彼此不同(不同的半径、不同的起点和终点等),并且元素的顺序因执行而异。例如,对于第一次执行,我有一个半径为 2 的圆,然后是另一个半径为 1 的圆,然后是一条长度为 4 的线,对于第二次执行,我有一条长度为 1 的线,然后是另一条长度为 5 的线一个不同的方向,然后是一个半径为 0.5 的圆。

我已经学会了如何组合向量,使其可以包含不同的类型,但到目前为止,每个元素的序列和定义都是硬编码的。现在我想让它变得灵活(最后序列和定义应该是文件驱动的)。为此,我尝试实现一个模板函数,该函数将输入的任何元素添加到向量中。当前定义也将向量作为输入,但我最终可能会将此函数定义为向量的方法。

不幸的是,我无法找到一种可行的方法。我知道我无法复制unique_ptr,所以我尝试了std::move() 方法但不起作用。我在第 671 行收到 xmemory 模块的 C2664 错误消息,说我无法将 T2 中的参数 1 转换为 std::nullptr_t。

有人可以帮我吗?太棒了!

这是实现我的代码基本思想的示例代码:



#include <iostream>
#include <vector>
#include <variant>


struct point
{
    double x;
    double y;
};

class segment
{
public:
    segment() 
    {
        P1.x = 0;
        P1.y = 0;

        P2.x = 0;
        P2.y = 0;
    };
    virtual ~segment() {};

    virtual double get_radius() { return 0; };
    virtual double get_length() { return 0; };
    virtual double get_angle() { return 0; };

    int segment_id = 0;

protected:
    point P1;
    point P2;
};

class Line : public segment
{
public:
    Line() {};
    Line(const point pt1, const point pt2)
    {
        P1.x = pt1.x;
        P1.y = pt1.y;

        P2.x = pt2.x;
        P2.y = pt2.y;

        segment_id = 1;
    };

    ~Line() {};

    double get_length() { return calc_length(); };
    double get_angle() { return calc_angle(); };

private:
    double calc_length()
    {
        // calculate length (here: dummy value)
        return 1;
    }

    double calc_angle()
    {
        // calculate angle (here: dummy value)
        return 0.5;
    }

    double length = 0;
    double angle = 0;
}
;

class circle : public segment
{
public:
    circle()
    {
        center.x = 0;
        center.y = 0;
    };
    circle(const double r, const point c)
    {
        radius = r;
        center.x = c.x;
        center.y = c.y;

        segment_id = 2;
    };

    ~circle() {};

    double get_radius() { return radius; };
    point get_center() { return center; };
    double get_length() { return 3.14 * radius; }; //returns circumference

private:
    double radius = 0;
    point center;
};

//-------------------------------------------------------
//T1: class type "segment", T2: class object Line or circle
template<typename T1, typename T2>
inline void add_segment(T1 v, T2 line_or_circle)
{
    v.emplace_back(line_or_circle);
}

//-------------------------------------------------------

int main()
{
    int nbr = 5;
    point start;
    start.x = 1;
    start.y = 2;

    point end;
    end.x = 3;
    end.y = 4;

    point c;
    c.x = 0;
    c.y = 0;

    double r = 9;

    auto anotherCircle = std::make_unique<circle>(r, c);
    auto anotherLine = std::make_unique<Line>(start, end);

    circle myCircle(r, c);
    
    //VERSION 1: Does now compile. 
    std::vector<std::unique_ptr<segment>> v1;
    v1.emplace_back(std::move(anotherCircle));
    v1.emplace_back(std::move(anotherLine));
    std::cout << v1[0]->get_radius() << std::endl;
    std::cout << v1[1]->segment_id << std::endl;

    //VERSION 2: Compiles
    std::vector<std::unique_ptr<segment>> v2;

    v2.emplace_back(std::make_unique<circle>(r, c));

    v2.emplace_back(std::make_unique<Line>(start, end));

    //=================================================================
    //now I want to implement this as a function call
    //=================================================================

    std::vector<std::unique_ptr<segment>> v3;

    //VERSION 5:
    auto myLine2 = std::make_unique<Line>(start, end);
    add_segment(v3, std::move(myLine2)); //shall add object of class Line or circle (derived from virtual segment class, see above) to vector v3. In this example a Line but might be a circle

}

【问题讨论】:

    标签: c++ pointers templates vector


    【解决方案1】:

    您的函数add_segment 正在按值获取向量。这无法编译,因为向量是不可复制的,因为唯一指针是不可复制的。即使你使用了可复制的指针类型,它也是一个没有意义的方法,因为副本在函数结束时被销毁。

    您还需要在add_segment 的正文中移动line_or_circle 参数。

    template<typename T1, typename T2>
    inline void add_segment(T1 & v, T2 line_or_circle)
    {
        v.emplace_back(std::move(line_or_circle));
    }
    

    【讨论】:

    • 非常感谢@Caleth!这正在做我想要实现的目标。并感谢您指出我没有引用 v 的错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多