重载非类型模板结构的成员结构的复制赋值运算符

Overload copy assignment operator for a member struct of a non-type template struct

本文关键字:结构 成员 复制 赋值运算符 类型 重载      更新时间:2023-10-16

我有以下非类型模板:

template<size_t MAX_SIZE>
struct Path{
    struct Point{
        float x;
        float y;
       }
    };
    Point segment[MAX_SIZE];
};

如果我现在声明两个不同的路径,我就不能将不同段的元素相互分配,因为结构可能具有相同的结构,但类型不同:

Path<10> path_a ;
Path<30> path_b ;
path_a.segment[0].x = 1;
path_a.segment[0].y = 2;
path_b.segment[0] = path_a.segment[0]; // <- error C2679 in Visual Studio)

当然,如果我把点和路径的定义分开,任务就会起作用:

struct Point{
        float x;
        float y;
       };
template<size_t MAX_SIZE>
struct Path{
    Point segment[MAX_SIZE];
};

但这不是我想要的(这只是一个MWE),所以我想知道如何重载复制分配运算符以使其工作。我尝试过许多变体,例如:

template<size_t MAX_SIZE>
struct Path{
    struct Point{
        float x;
        float y;
        template<size_t OTHER_SIZE>
        Point & operator = (const typename Path<OTHER_SIZE>::Point & that)
        {
            x = that.x;
            y = that.y;
            return *this;
        }
    };
    Point segment[MAX_SIZE];
};

但我总是犯同样的错误。所以我的问题是:是否有可能在不改变结构布局的情况下,以允许以下形式赋值的方式重载=?

path_b.segment[0] = path_a.segment[0];

是的,这样的设置是可能的。在核心,你需要一个可以接受所有类型的分配操作员模板:

template<class T>
Point & operator = (const T & that)

作为一个基本的解决方案,这就足够了。它现在将处理所有具有兼容类型的成员xy的类型,并为不兼容的类型生成(通常)丑陋的错误消息。

如果这对你来说足够好的话,我们就完了。

如果您有赋值运算符的其他重载,您可能希望选择性地禁用模板运算符。为此,您需要对Point类进行检测,并使用SFINAE:

template<size_t MAX_SIZE>
struct Path{
    struct Point{
        float x;
        float y;
        struct EnableAssignment {};
    };
    Point segment[MAX_SIZE];
};

然后像这样使用仪器:

template<class T, class U = typename T::EnableAssignment>
Point & operator = (const T & that)

【简化实例】


上面的代码在函数模板中使用了一个默认的模板参数,该参数仅在C++11中引入。在此之前,您必须以其他方式调用SFINAE:

template <class L, class R>
struct SfinaeThenRight
{
  typedef R type;
};
template <class T>
typename SfinaeThenRight<typename T::EnableAssignment, Point&>::type operator = (const T & that)

[简化C++98实例]

template<size_t OTHER_SIZE>
Point & operator = (const typename Path<OTHER_SIZE>::Point & that)

无法工作,因为无法推导出外部结构上的模板参数OTHER_SIZE。你可以:

template<typename T>
Point & operator = (const T & that)
{
    x = that.x;
    y = that.y;
    return *this;
}

请注意,如果没有成员xy的东西被传递,您将得到一个编译器错误,这对于这种情况来说应该足够了。

实时