Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.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++ Const方法和自定义迭代器_C++_Oop_Templates_Iterator - Fatal编程技术网

C++ Const方法和自定义迭代器

C++ Const方法和自定义迭代器,c++,oop,templates,iterator,C++,Oop,Templates,Iterator,我有一个类包含一个std::vector,另一个类是该类的自定义迭代器。它对于非常量方法非常有效,但当我尝试在const方法中创建迭代器时,编译器失败,因为它无法将const\u迭代器转换为迭代器。例如,下面的代码失败,但如果对ConstFunc的调用被注释掉,则编译并运行良好 #include <vector> template <class T> class FooIter { public: typename std::vector<T>::i

我有一个类包含一个
std::vector
,另一个类是该类的自定义
迭代器。它对于非常量方法非常有效,但当我尝试在
const
方法中创建
迭代器时,编译器失败,因为它无法将
const\u迭代器
转换为
迭代器
。例如,下面的代码失败,但如果对
ConstFunc
的调用被注释掉,则编译并运行良好

#include <vector>

template <class T>
class FooIter {
public:
    typename std::vector<T>::iterator iterator;

    FooIter(std::vector<T> &vec) {iterator = vec.begin();}
};

template <class T>
class Foo {
public:
    std::vector<T> vec;

    Foo() {}
    void NonConstFunc() {
        FooIter<T> iter(vec);
    }
    void ConstFunc() const {
        FooIter<T> iter(vec);
    }
};

int main()
{
    Foo<int> foo;
    foo.NonConstFunc();
    foo.ConstFunc();
    return 0;
}

Matrix2d
是“Foo”,而
Matrix2dIterator
是“FooIter”
find
需要迭代保存矩阵数据的
std::vector
,但它不会更改该数据。

原因是,您可以通过
std::vector::iterator
修改
vec
,从而修改类。因此,不能将它们放在
const
成员函数中。更技术性的原因是,在
const
成员函数中,所有成员都是
const
,并且
std::vector
具有这些函数

std::vector<T>::iterator begin();
std::vector<T>::const_iterator begin() const;
std::vector<T>::const_iterator cbegin() const;
或者,不在向量的值类型上设置模板,而是在向量本身上设置模板,这会自动检测
const
-ness:

#包括
样板
福伊特级{
公众:
decltype(std::declval().begin())迭代器;
FooIter(T&vec){iterator=vec.begin();}
};
样板
福班{
公众:
std::vec;
Foo(){}
void nonstfunc(){
国际热核聚变实验堆(vec);
}
void ConstFunc()常量{
国际热核聚变实验堆(vec);
}
};
int main()
{
富富,;
foo.noncostfunc();
foo.ConstFunc();
返回0;
}
请注意,这并不意味着您只剩下一个类。两种方法中的
iter
s将是不同类型的(
FooIter
vs
FooIter
)。优点是编译器将为您编写这两个类,从而减少代码重复,因为这两个类几乎相同

这是不利的。要知道现在使用的是哪个变量并不容易,在非
const
上下文中使用
const
迭代器(如果不打算修改任何内容,您应该始终这样做)有点棘手,因为
FooIter(vec)
vec
不是const时总是返回非
const
变量


编辑:添加了一些模板魔术,只允许
std::vector
,即
std::set s;FooIter f{s}将不再编译。

您应该选择n314159的解决方案之一。我只是想说明使
FooIter
同时适用于非常量和常量向量的问题

您可以将重载构造函数添加到
FooIter
,该构造函数采用常量引用:

FooIter(const std::vector<T> &vec) {iterator = vec.begin();}
但是其他成员函数需要知道使用哪一个。您可以为此添加一个标志变量,但这将是相当低效的;它需要更多的内存(除了迭代器本身的重复),并且需要对每个成员函数调用进行检查。因此,最好的解决方案是有两个独立的迭代器类,一个用于非常量,另一个用于常量。

也许

#include <vector>
using namespace std;


    template <class T>
    class FooIter {
    public:
        const typename vector<T>::iterator itr;         // const added

        FooIter(vector<T> &vec) : itr{vec.begin()} {}
    };

    template <class T>
    class Foo {
    public:
        vector<T> vec;

        Foo() {}
        void NonConstFunc() {
                FooIter<T> iter(vec);
        }
        void ConstFunc()  {                 // const removed, if
                FooIter<T> iter(vec);       // needed prefix it on each needed line
        }
    };

    int main()  {
        Foo<int> foo;
        foo.NonConstFunc();
        foo.ConstFunc();
        return 0;
    }
#包括
使用名称空间std;
样板
福伊特级{
公众:
常量typename向量::迭代器itr;//添加了常量
FooIter(vector&vec):itr{vec.begin()}{}
};
样板
福班{
公众:
向量向量机;
Foo(){}
void nonstfunc(){
国际热核聚变实验堆(vec);
}
void ConstFunc(){//const已删除,如果
FooIter iter(vec);//需要在每一行加上前缀
}
};
int main(){
富富,;
foo.noncostfunc();
foo.ConstFunc();
返回0;
}

您可能需要一个
FooIter
和一个
ConstFooIter
,因为
iterator
const\u iterator
是不同的类型。你可以用
union
/
variant
做一些奇怪的事情,但这会让你的代码难以阅读。以我的经验,试图使
iterator
const\u iterator
类型相同是行不通的。您计划如何在
const
方法中使用
FooIter
呢?您可以尝试对
FooIter
类使用一些额外的模板参数化,但通常情况下,为iterator和const使用两种不同的类型比较容易常量迭代器。@rustyx我在问题中添加了一个我打算如何使用常量迭代器的示例。伙计,我不知道我对模板的了解有多少。我甚至不知道std::enable_if_t之类的东西存在。谢谢你启发我,并把这些放在一起行,我应该为FooIter使用什么模板专门化?我知道它应该是类似于国际热核实验堆(vec)的东西
,但我不知道用什么来替换问号。只需使用
FooIter
FooIter
。第二个参数有缺省值,不必(实际上也不应该)提供。@ JimLoad模板元编程是C++中一个有趣的兔子洞。
typename std::vector<T>::iterator iterator;
typename std::vector<T>::const_iterator const_iterator;

FooIter(std::vector<T> &vec) {iterator = vec.begin();}
FooIter(const std::vector<T> &vec) {const_iterator = vec.begin();}
#include <vector>
using namespace std;


    template <class T>
    class FooIter {
    public:
        const typename vector<T>::iterator itr;         // const added

        FooIter(vector<T> &vec) : itr{vec.begin()} {}
    };

    template <class T>
    class Foo {
    public:
        vector<T> vec;

        Foo() {}
        void NonConstFunc() {
                FooIter<T> iter(vec);
        }
        void ConstFunc()  {                 // const removed, if
                FooIter<T> iter(vec);       // needed prefix it on each needed line
        }
    };

    int main()  {
        Foo<int> foo;
        foo.NonConstFunc();
        foo.ConstFunc();
        return 0;
    }