2016-04-06 37 views
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]; 
+1

只是为了确保你是不是X-Y'ing这一点,你可以详细说明*为什么*每个路径的点必须是一个独特的类型,但仍然可以相互分配? –

+0

@MarkB,这是无关紧要的问题。这个问题本身就是有效的。指定不同外层模板的内部结构本身就是一个有效的东西。 – SergeyA

+0

@MarkB:主要原因是我有点固执,真的很想知道是否有办法让它工作。此外,对于此处介绍的简单示例,可能有一种解决方法,但不是一般情况下的解决方案,因为它可能需要对现有代码库进行多处更改。 – magnetometer

回答

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) 

[Simplified live example]


上面的代码使用函数模板中的默认模板参数,仅在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) 

[Simplified C++98 live example]

+0

是的,这是更好的方法。这就是我一直在寻找的东西,但是你击败了我。只需修复您的代码即可编译。 – SergeyA

+0

@SergeyA究竟是什么错误呢? – Angew

+0

只需尝试编译它。您的operator =签名不正确。点不是您可以使用的类型,它是Path的一种内部类型(或将其放入Point的定义中)。 – SergeyA

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; 
} 

注意,如果传递的东西,而不成员xy你会得到一个编译器错误,这应该是足够的这种情况。

LIVE

+0

这是一个可怕的解决方案。它会很乐意吃任何**,其中有x和y,并掩盖了程序中潜在的逻辑错误。 – SergeyA

+0

@SergeyA OP的情况应该足够了。如果某些不兼容的东西作为rhs传递,我们会得到一个编译器错误。不必要的复杂性也可能会受到伤害。 – songyuanyao

+0

问题不在于没有x或y的东西。问题出在某些方面,但与Pointer没有任何关系。 – SergeyA