c++ - 从具有运算符重载的模板化类继承。 'operator*' 的不明确过载

标签 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_;
};

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

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

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

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*;
                               ^

任何人都可以解释为什么运算符在子类中没有正确解析但它们在基类中?如果我必须做类似 using Array<T,3>::operator... 的事情应该怎么写?

谢谢!

最佳答案

您会收到这些错误,因为当编译器尝试匹配运算符参数时,它将强制对基类执行额外的向下转换,而在基类实例上调用相同的运算符时它会获得完全匹配。您应该对 M 的类型施加额外的限制使用 ::std::enable_if ,像这样:

template
<
     typename M
,    typename TEnable = typename ::std::enable_if_t
     <
         ::std::is_integral<M>::value
         ||
         ::std::is_floating_point<M>::value
     >
>

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

关于c++ - 从具有运算符重载的模板化类继承。 'operator*' 的不明确过载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46028454/

相关文章:

c++ - 编译器编译一个 'io_service_' 变量显示为 : cannot appear in a constant-expression

c++ - 如何在Windows CE环境下使用UnitTest++?

c++ - 二进制 '[' : no operator found which takes a left-hand operand of type 'const std::map<_Kty,_Ty>'

swift - Xcode 14 : Custom templates don't appear in Swift Package file creation

swift - 如何在 Swift 中需要 super 协议(protocol)类型的地方传递子协议(protocol)类型? (考虑为基类类型传递子类类型但为协议(protocol))

java - 一个对象可以包含它的父类(super class)吗?

c++ - 无法解决循环依赖

c++ - 如何使用相应的 X509 证书验证私有(private) RSA 签名

c++ - 如何判断是否为 PE Win32 启用了 GS 编译器

c++ - 重载采用 chrono::duration 的函数