从带有运算符重载的模板化类继承。 “运营商*”的模糊过载

时间:2017-09-03 22:47:16

标签: c++ templates inheritance

出于学习目的,我正在尝试使用模板化类和继承。其中一件事是我希望我的课程能够使用+=+-=-*,{{为了这个目的,我开发了一个基本上是数据数组的类:

*=

我使用以下代码测试了这个类,没有任何问题:

template<typename T, int N>
class Array
{
public:
    // Constructor
    Array( T value = T(0))
    {
        /* Initialize the array with the same value everywhere */
    }
    template<typename M>
    Array(const Array<M,N>& other)
    {
        /* Copy constructor allowing for type change */
    }

    // Destructor
    ~Array()
    {
        /* no need to call any destructor since it is a smart pointer */    
    }

    // Product
    template<typename M>
    Array<T,N>& operator*=(const M& rhs)
    {
        /* implementation */
    }
    template<typename M>
    friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs)
    {
        /* implementation */
    }
    template<typename M>
    friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs)
    {
        /* implementation */
    }
    Array<T,N>& operator*=(const Array<T,N>& rhs)
    {
        /* implementation */
    }
    friend Array<T,N> operator*(const Array<T,N>& lhs,const Array<T,N>& rhs)
    {
        /* implementation */
    }

    // String
    std::string str() const
    {
        /* return a string containing the array */
    }

private:
    std::shared_ptr<T> data_;
    size_t n_;
};

然后,我从这个数组继承来创建一个大小为3的数组,其中包含一个特定的成员函数

// Test friend Array<T,N> operator*(const Array<T,N>& lhs,const Array<T,N>& rhs)
Array<double,2> array1(1);
std::cout<<"array1: "<<array1.str()<<std::endl;
Array<double,2> array2(2);
std::cout<<"array2: "<<array2.str()<<std::endl;
Array<int,2> array3 = array1*array2;
std::cout<<"array3: array1*array2"<<array3.str()<<std::endl;

// Test friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs)
Array<double,2> array4 = 2*array1;
std::cout<<"array4: 2*array1"<<array4.str()<<std::endl;

// Test friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs)
Array<double,2> array5 = array1*5;
std::cout<<"array5: array1*3"<<array5.str()<<std::endl;

我想按如下方式使用它(注意它与template<typename T> class Vector3: public Array<T,3> { public: // Use Array constructors using Array<T,3>::Array; // Specific function template<typename M> Vector3 crossProduct(const Vector3& other) { /* implementation */ } }; 之前的相同,但Array<T,N>}:

Vector3<T>

编译时,我得到以下错误:

// Test friend Array<T,N> operator*(const Array<T,N>& lhs,const Array<T,N>& rhs)
Vector3<double> vector1(1);
std::cout<<"vector1: "<<vector1.str()<<std::endl;
Vector3<double> vector2(2);
std::cout<<"vector2: "<<vector2.str()<<std::endl;
Vector3<int> vector3 = vector1*vector2;
std::cout<<"vector3: vector1*vector2"<<vector3.str()<<std::endl;

// Test friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs)
Vector3<double> vector4 = 2*vector1;
std::cout<<"vector4: 2*vector1"<<vector4.str()<<std::endl;

// Test friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs)
Vector3<double> vector5 = vector1*5;
std::cout<<"vector5: vector1*3"<<vector5.str()<<std::endl;

我不明白为什么继承类我得到错误而基类没有。我试过添加error: ambiguous overload for 'operator*' (operand types are 'Vector3<double>' and 'Vector3<double>') Vector3<int> vector3 = vector1*vector2; ^ note: candidates are: note: Array<T, N> operator*(M, const Array<T, N>&) [with M = Vector3<double>; T = int; int N = 3] friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs) ^ note: Array<T, N> operator*(const Array<T, N>&, const M&) [with M = Vector3<double>; T = int; int N = 3] friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs) ^ note: Array<T, N> operator*(M, const Array<T, N>&) [with M = Vector3<double>; T = double; int N = 3] friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs) ^ note: Array<T, N> operator*(const Array<T, N>&, const M&) [with M = Vector3<double>; T = double; int N = 3] friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs) ^ note: Array<double, 3> operator*(const Array<double, 3>&, const Array<double, 3>&) friend Array<T,N> operator*(const Array<T,N>& lhs,const Array<T,N>& rhs) ^ warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default] Vector3<double> vector4 = 2*vector1; ^ note: candidate 1: Array<T, N> operator*(M, const Array<T, N>&) [with M = int; T = double; int N = 3] friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs) ^ note: candidate 2: Array<T, N> operator*(const Array<T, N>&, const M&) [with M = Vector3<double>; T = int; int N = 3] friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs) ^ warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default] Vector3<double> vector4 = 2*vector1; ^ note: candidate 1: Array<T, N> operator*(M, const Array<T, N>&) [with M = int; T = double; int N = 3] friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs) ^ note: candidate 2: Array<T, N> operator*(const Array<T, N>&, const M&) [with M = Vector3<double>; T = double; int N = 2] friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs) ^ warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default] Vector3<double> vector4 = 2*vector1; ^ note: candidate 1: Array<T, N> operator*(M, const Array<T, N>&) [with M = int; T = double; int N = 3] friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs) ^ note: candidate 2: Array<T, N> operator*(const Array<T, N>&, const M&) [with M = Vector3<double>; T = int; int N = 2] friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs) ^ warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default] Vector3<double> vector4 = 2*vector1; ^ note: candidate 1: Array<T, N> operator*(M, const Array<T, N>&) [with M = int; T = double; int N = 3] friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs) ^ note: candidate 2: Array<T, N> operator*(const Array<T, N>&, const M&) [with M = Vector3<double>; T = double; int N = 3] friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs) ^ warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default] Vector3<double> vector5 = vector1*5; ^ note: candidate 1: Array<T, N> operator*(const Array<T, N>&, const M&) [with M = int; T = double; int N = 3] friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs) ^ note: candidate 2: Array<T, N> operator*(M, const Array<T, N>&) [with M = Vector3<double>; T = int; int N = 3] friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs) ^ warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default] Vector3<double> vector5 = vector1*5; ^ note: candidate 1: Array<T, N> operator*(const Array<T, N>&, const M&) [with M = int; T = double; int N = 3] friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs) ^ note: candidate 2: Array<T, N> operator*(M, const Array<T, N>&) [with M = Vector3<double>; T = double; int N = 2] friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs) ^ warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default] Vector3<double> vector5 = vector1*5; ^ note: candidate 1: Array<T, N> operator*(const Array<T, N>&, const M&) [with M = int; T = double; int N = 3] friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs) ^ note: candidate 2: Array<T, N> operator*(M, const Array<T, N>&) [with M = Vector3<double>; T = int; int N = 2] friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs) ^ warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default] Vector3<double> vector5 = vector1*5; ^ note: candidate 1: Array<T, N> operator*(const Array<T, N>&, const M&) [with M = int; T = double; int N = 3] friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs) ^ note: candidate 2: Array<T, N> operator*(M, const Array<T, N>&) [with M = Vector3<double>; T = double; int N = 3] friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs) ^ ,但编译器也抱怨这一行:

using Array<T,3>::operator*

任何人都可以解释为什么在子类中没有正确解析运算符但是它们在基类中?如果我必须做error: no members matching 'Array<double, 3>::operator*' in 'class Array<double, 3>' using Array<T,3>::operator*; ^ 这样的事情我应该怎么写呢?

谢谢!

2 个答案:

答案 0 :(得分:1)

您遇到这些错误是因为当编译器尝试匹配运算符参数时,将强制执行额外的向下转换为基类,而在基类实例上调用相同的运算符时会获得完全匹配。您应该使用::std::enable_iftemplate < typename M , typename TEnable = typename ::std::enable_if_t < ::std::is_integral<M>::value || ::std::is_floating_point<M>::value > > 的类型设置其他限制,如下所示:

operator*

Array<T,3>类中没有{{1}},因为您将*运算符声明为非成员友元函数模板。

答案 1 :(得分:0)

在VTT提供的提示之后,我能够修复代码。由于我不使用c ++ 14,我设法在没有std::enable_if_t的情况下完成了。这是最终的运营商:

// Product
template<typename M, typename std::enable_if<!std::is_base_of<Array<T,N>,M>::value>::type>
Array<T,N>& operator*=(const M& rhs)
{
    /* implementation */
}
template<typename M, typename std::enable_if<!std::is_base_of<Array<T,N>,M>::value>::type>
friend Array<T,N> operator*(const Array<T,N>& lhs,const M& rhs)
{
    /* implementation */
}
template<typename M, typename std::enable_if<!std::is_base_of<Array<T,N>,M>::value>::type>
friend Array<T,N> operator*( M lhs, const Array<T,N>& rhs)
{
    /* implementation */
}
Array<T,N>& operator*=(const Array<T,N>& rhs)
{
    /* implementation */
}
friend Array<T,N> operator*(const Array<T,N>& lhs,const Array<T,N>& rhs)
{
    /* implementation */
}

希望这会对其他人有所帮助。