如何编写将变体类类型的对象添加到向量的模板函数? [英] How to write a template function that adds an object of variant class type to a vector?

查看:20
本文介绍了如何编写将变体类类型的对象添加到向量的模板函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

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

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

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

<预><代码>#include #include <向量>#include <变体>结构点{双 x;双y;};班级{民众:部分(){P1.x = 0;P1.y = 0;P2.x = 0;P2.y = 0;};虚拟 ~segment() {};虚拟双 get_radius() { 返回 0;};虚拟双 get_length() { 返回 0;};虚拟双 get_angle() { 返回 0;};int segment_id = 0;受保护:P1点;P2点;};班级线路:公共段{民众:线() {};线(常量点 pt1,常量点 pt2){P1.x = pt1.x;P1.y = pt1.y;P2.x = pt2.x;P2.y = pt2.y;段 ID = 1;};〜线(){};double get_length() { return calc_length();};double get_angle() { return calc_angle();};私人的:双 calc_length(){//计算长度(此处:虚拟值)返回 1;}双 calc_angle(){//计算角度(此处:虚拟值)返回 0.5;}双倍长度 = 0;双角 = 0;};班级圈:公共环节{民众:圆圈(){中心.x = 0;中心.y = 0;};圆(常量双 r,常量点 c){半径 = r;中心.x = c.x;中心.y = c.y;段 ID = 2;};〜圈(){};double get_radius() { 返回半径;};点 get_center() { 返回中心;};double get_length() { 返回 3.14 * 半径;};//返回周长私人的:双半径 = 0;点中心;};//-------------------------------------------------------//T1:类类型段",T2:类对象线或圆templateinline void add_segment(T1 v, T2 line_or_circle){v.emplace_back(line_or_circle);}//-------------------------------------------------------int main(){int nbr = 5;点开始;开始.x = 1;开始.y = 2;点结束;结束.x = 3;结束.y = 4;c点;c.x = 0;c.y = 0;双 r = 9;auto anotherCircle = std::make_unique(r, c);auto anotherLine = std::make_unique(start, end);圈 myCircle(r, c);//版本1:现在编译.std::vector>v1;v1.emplace_back(std::move(anotherCircle));v1.emplace_back(std::move(anotherLine));std::cout <<v1[0]->get_radius()<segment_id <>v2;v2.emplace_back(std::make_unique(r, c));v2.emplace_back(std::make_unique(start, end));//==================================================================//现在我想将其实现为函数调用//==================================================================std::vector>v3;//版本5:auto myLine2 = std::make_unique(start, end);add_segment(v3, std::move(myLine2));//应将 Line 或 circle 类(派生自虚拟线段类,见上文)的对象添加到向量 v3.在这个例子中,一条线但可能是一个圆}

解决方案

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

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

templateinline void add_segment(T1 & v, T2 line_or_circle){v.emplace_back(std::move(line_or_circle));}

I have another problem that I have no idea how to solve. Maybe somebody can help me.

What I want to do: I have a vector that shall take elements of various class types. In my example code I have two classes (Line, circle) that are both derived from a virtual class segment. My code shall chain several circle or Line elements and put them in the vector. Each element may be different from the other (different radii, different starting and ending points, etc) and the sequence of elements shall vary from execution to execution. That is for instance for the first execution I have a circle with radius 2 followed by another circle of radius 1, followed by a Line of length 4 and for the second execution I have a Line of length 1 followed by another Line of Length 5 in a different direction, followed by a circle of radius 0.5.

I've already learned how to compose the vector such that it can contain different types but as of now the sequence and definition of each element is hard-coded. Now I want to make this flexible (in the end the sequence and definition shall be file-driven). For this I attempt to implement a template function that takes whatever element is fed into it and adds it to the vector. The current definition also takes the vector as input but I may end up to define this function as a method for the vector.

Unfortunately I cannot figure out a way how to do it that works. I understand that I cannot copy a unique_ptr so I tried with the std::move() method but doesn't work. I get an C2664 error message of the xmemory module in line 671 saying that I cannot convert argument 1 in T2 into a std::nullptr_t.

Can somebody help me here? That'll be so awesome!

Here's my example code that implements the basic idea for my code:



#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

}

解决方案

Your function add_segment is taking the vector by value. This fails to compile because the vector is uncopyable, as unique pointers are uncopyable. Even if you used a copyable pointer type, it would be a pointless method as the copy is destroyed at the end of the function.

You will also need to move the line_or_circle parameter in the body of add_segment.

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

这篇关于如何编写将变体类类型的对象添加到向量的模板函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆