9

我有以下非类型模板:

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];
4

2 回答 2

5

是的,这样的设置是可能的。在核心,您需要一个可以接受所有类型的赋值运算符模板:

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 实例】

于 2016-04-06T14:54:07.453 回答
2
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;
}

请注意,如果没有成员x并被y传递,您将收到编译器错误,这对于这种情况应该足够了。

居住

于 2016-04-06T14:51:41.393 回答