简体   繁体   English

为什么在不是“*this”的任何东西上使用基于范围的 for 循环时,我会得到“与 operator* 不匹配”?

[英]Why am I getting a “no match for operator*” when using range-based for loop on anything that isn't “*this”?

I'm currently writing some utility functions for a templated container class for which the iterator seems to be working just fine.我目前正在为模板化容器 class 编写一些实用程序函数,迭代器似乎工作得很好。 For example, the following code compiles and works as expected: (Class name Mat, containing type T)例如,以下代码按预期编译和工作:(类名 Mat,包含类型 T)

void scalarFill(T x){
    for(auto& i : *this){
        i = x;
    }
}`

However, when I call the range-based for loop on an a newly instantiated container, I get "error: no match for 'operator*' (operand type is 'MatIter')" such as in the following code:但是,当我在新实例化的容器上调用基于范围的 for 循环时,我得到“错误:'operator*' 不匹配(操作数类型为'MatIter')”,例如以下代码:

static Mat zeros(size_t a){
    Mat<double> result(a);
    for(auto& i: result){
        i = 0;
    }
    return result;
}

I've explicitly defined the iterator for my class, and there is certainly an 'operator*' function.我已经为我的 class 明确定义了迭代器,并且肯定有一个“操作员*”function。 Is there something I'm missing about how range-based for loops work?关于基于范围的 for 循环如何工作,我有什么遗漏吗? The following is a stripped down version of the full program which reproduces the error:以下是重现错误的完整程序的精简版:

#include <stdlib.h>
#include <stdio.h>
using namespace std;

template <class T>
class MatIter;

template <class T = double>
class Mat {
    friend class MatIter<T>;

    public:
    size_t columns = 0;
    T* data;

    MatIter<T> begin(){
        return MatIter<T>(*this, 0);
    }
    MatIter<T> end(){
        return MatIter<T>(*this, columns);
    }
    Mat(size_t a){
        columns = a;
        data = new T[a];
    }
    ~Mat(){
        delete []data;
    }
    //This function compiles and works as expected
    void scalarFill(T x){
        for(auto& i : *this){
            i = x;
        }
    }
    //this function throws "error: no match for 'operator*' (operand type is 'Matiter<double>')"
    static Mat zeros(size_t a){
        Mat<double> result(a);
        for(auto& i: result){
            i = 0;
        }
        return result;
    }
};

template <class T>
class MatIter{
    public:
    Mat<T>& matrix;
    size_t position;
    MatIter(Mat<T>& mat, size_t pos) : matrix(mat), position(pos){}
    
    bool operator==(MatIter b){
        if(position == b.position) return true;
        else return false;
    }
    bool operator!=(MatIter b){
        if(position != b.position) return true;
        else return false;
    }
    MatIter& operator++(){
        position++;
        return *this;
    }
    MatIter operator++(int){
        MatIter<T> clone(*this);
        position++;
        return clone;
    }
    T & operator*(){
        return matrix.data[position];
    }
};

int main(){
    Mat<> test(7);
    test.scalarFill(5);
    for(size_t i = 0; i < test.columns-1; i++){
        printf("%g, ", test.data[i]);
    }
    printf("%g\n", test.data[test.columns-1]);

    test = Mat<double>::zeros(7);
    for(size_t i = 0; i < test.columns-1; i++){
        printf("%g, ", test.data[i]);
    }
    printf("%g\n", test.data[test.columns-1]);

    return 0;
}

Any insights would be greatly appreciated!任何见解将不胜感激!

This fails because at the point where the compiler sees this loop, it has not yet seen a definition for the MatIter template;这失败了,因为在编译器看到这个循环的时候,它还没有看到MatIter模板的定义; MatIter<double> is therefore an incomplete type, so the compiler doesn't know about the operator* member function yet. MatIter<double>因此是一个不完整的类型,所以编译器还不知道operator*成员 function。

However, the result variable shouldn't even be Mat<double> here, it should just be Mat (which is the same as Mat<T> ).但是, result变量在这里甚至不应该是Mat<double> ,它应该只是Mat (与Mat<T>相同)。 Changing the type of result to Mat solves the problem.result类型更改为Mat可以解决问题。 It forces the compiler to wait to figure out if the body is valid until it knows what T is, and by then MatIter has a definition, and the compiler can find the operator* function.它强制编译器等待确定主体是否有效,直到它知道T是什么,然后MatIter有了定义,编译器可以找到operator* function。

Then you have a double-free problem because your Mat template violates the rule of five -- the implicit copy and move constructor/assignment operations cause dual ownership of the data pointer.然后你有一个双重释放问题,因为你的Mat模板违反了五规则——隐式复制和移动构造函数/赋值操作导致data指针的双重所有权。 The object returned out of Mat::zeros() is used as the source of move-assignment to test in main() .Mat::zeros()返回的 object 用作在main()test的移动分配源。 This copies the data pointer to test but then the returned temporary is destroyed, which causes the data pointer to be deleted, freeing the allocated memory.这会将data指针复制到test ,但随后返回的临时对象被破坏,这会导致data指针被删除,从而释放分配的 memory。 Then test is destroyed, and the same pointer value is deleted a second time.然后test被销毁,同样的指针值被第二次删除。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM