Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在正确的全局运算符上推导出错误的成员运算符_C++_Templates_Operator Overloading - Fatal编程技术网

C++ 在正确的全局运算符上推导出错误的成员运算符

C++ 在正确的全局运算符上推导出错误的成员运算符,c++,templates,operator-overloading,C++,Templates,Operator Overloading,我有一个3x3矩阵和一个3x1向量类。我有两个乘法运算符;一个用于将矩阵与标量相乘,另一个用于将矩阵与向量对象相乘。矩阵标量乘法运算符是矩阵类中的成员,矩阵向量乘法运算符是全局的 #include <initializer_list> #include <array> template <class T> class Matrix { public: Matrix(std::initializer_list<T> List

我有一个3x3
矩阵
和一个3x1
向量
类。我有两个乘法运算符;一个用于将矩阵与标量相乘,另一个用于将矩阵与向量对象相乘。矩阵标量乘法运算符是
矩阵
类中的成员,矩阵向量乘法运算符是全局的

#include <initializer_list>
#include <array>

template <class T>
class Matrix
{
    public:
        Matrix(std::initializer_list<T> List);
        Matrix() : Matrix({0,0,0,0,0,0,0,0,0}) {}

        template <class S>                      // THE COMPILER TRIES TO USE
        Matrix<T> operator*(const S & Scalar);  // THIS OPERATOR IN BOTH CASES.

        const T & operator()(size_t i, size_t j) const;

    private:
        static constexpr size_t SIZE = 3;
        static constexpr size_t AREA = SIZE * SIZE;
        std::array<T, AREA> E;
};

template <class T>
Matrix<T>::Matrix(std::initializer_list<T> List)
{
    if (List.size() != AREA) throw("Error!");
    for (size_t i=0; i<AREA; i++)
    {
        E[i] = *(List.begin() + i);
    }
}

template <class T>
const T & Matrix<T>::operator()(size_t i, size_t j) const
{
    return E[SIZE * j + i];
}

template <class T>
template <class S>
Matrix<T> Matrix<T>::operator*(const S & Scalar)
{
    const T ScalarT = static_cast<T>(Scalar);
    Matrix<T> Result;
    for (size_t i=0; i<AREA; i++)
    {
        Result.E[i] = E[i] * ScalarT;
    }
    return Result;
}

template <class T>
class Vector
{
    public:
        Vector(std::initializer_list<T> List);
        Vector() : Vector({0,0,0}) {};
        const T & operator()(size_t i) const;
              T & operator()(size_t i);

    private:
        static constexpr size_t SIZE = 3;
        std::array<T, SIZE> E;
};

template <class T>
Vector<T>::Vector(std::initializer_list<T> List)
{
    if (List.size() != SIZE) throw("Error!");
    for (size_t i=0; i<SIZE; i++)
    {
        E[i] = *(List.begin() + i);
    }
}

template <class T>
const T & Vector<T>::operator()(size_t i) const
{
    return E[i];
}

template <class T>
T & Vector<T>::operator()(size_t i)
{
    return E[i];
}

template <class T>  // THE COMPILER NEVER TRIES USING THIS GLOBAL OPERATOR.
Vector<T> operator*(const Matrix<T> & Mat, const Vector<T> & Vec)
{
    Vector<T> Result;
    Result(0) = Mat(0,0) * Vec(0) + Mat(0,1) * Vec(1) + Mat(0,2) * Vec(2);
    Result(1) = Mat(1,0) * Vec(0) + Mat(1,1) * Vec(1) + Mat(1,2) * Vec(2);
    Result(2) = Mat(2,0) * Vec(0) + Mat(2,1) * Vec(1) + Mat(2,2) * Vec(2);
    return Result;
}

int wmain(int argc, wchar_t *argv[]/*, wchar_t *envp[]*/)
{
    Matrix<float> Mat1({2,  0,  0,
                        0,  2,  0,
                        0,  0,  2});

    Vector<float> Vec1({1,
                        2,
                        3});

    Matrix<float> Mat2 = Mat1 * 2;      // Matrix-Scalar Multiplication
    Vector<float> Vec2 = Mat1 * Vec1;   // Matrix-Vector Multiplication

    return 0;
}
#包括
#包括
模板
类矩阵
{
公众:
矩阵(标准:初始值设定项列表);
矩阵():矩阵({0,0,0,0,0,0,0,0}){
模板//编译器尝试使用
矩阵运算符*(常数S和标量);//这两种情况下都使用此运算符。
常量T&运算符()(大小i,大小j)常量;
私人:
静态constexpr size\u t size=3;
静态constexpr size\u t面积=大小*大小;
std::数组E;
};
模板
矩阵::矩阵(std::初始值设定项\u列表)
{
如果(List.size()!=区域)抛出(“错误!”);

对于(size_t i=0;i,该语言在搜索重载以检查所有可能的作用域时没有指定。一旦找到一个候选,则仅使用该作用域中的重载来选择最佳候选。如果该候选由于其他原因未能编译,它仍然不会检查其他作用域

因此,在您的例子中,由于标量是一个模板参数,它将匹配任何类型,因此只要运算符的左侧操作数是一个
矩阵
,标量乘法将匹配任何右侧操作数

你可以:

  • 只需将两个
    操作符*
    设置在同一范围内,这样就可以考虑解决重载问题
  • 更改标量
    操作符
    以获取一个
    标量
    为例,它是标量类型而不是泛型模板类型的薄包装

在搜索重载以检查所有可能的作用域时,该语言没有指定。一旦找到一个候选,只有该作用域中的重载用于选择最佳候选。如果该候选由于其他原因未能编译,它仍然不会检查其他作用域

因此,在您的例子中,由于标量是一个模板参数,它将匹配任何类型,因此只要运算符的左侧操作数是一个
矩阵
,标量乘法将匹配任何右侧操作数

你可以:

  • 只需将两个
    操作符*
    设置在同一范围内,这样就可以考虑解决重载问题
  • 更改标量
    操作符
    以获取一个
    标量
    为例,它是标量类型而不是泛型模板类型的薄包装

你能给出一个简单的例子吗?这有很多不必要的细节。
模板
(常量&)
匹配所有对象。它并不意味着“仅标量类型”或者,当使用同一运算符的成员和非成员版本时,重载解析会变得非常复杂。我强烈建议只使用非成员
运算符*
(这可能不会解决您的问题,但可能会消除一些杂念或混淆因素),使其成为
矩阵运算符*(常量和标量)const
@M.M偏序使得
const Vector&
const S&
更受欢迎,在成员运算符和非成员运算符中没有什么会变得复杂,至少在这里,成员
运算符*
应该是const限定的,尽管clang仍然发现模棱两可,你能给出一个最小的示例吗?这有很多不必要的详细信息。
模板
(const S&)
匹配所有对象。这并不意味着“仅标量类型”或某些内容当具有相同运算符的成员和非成员版本时,重载解析会变得非常复杂。我强烈建议只使用非成员的
运算符*
。(这可能无法解决您的问题,但可能会消除一些杂念或混淆因素)使其成为
矩阵运算符*(常数S&Scalar)const
@M.M偏序使得
const向量&
const S&
更受欢迎,在成员运算符和非成员运算符中没有什么复杂的事情,至少在这里,成员
运算符*
应该是const限定的,尽管clang仍然认为这是不明确的