Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.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++;使用自定义类_C++_List_C++11_Foreach - Fatal编程技术网

C++ 如何在C++;使用自定义类

C++ 如何在C++;使用自定义类,c++,list,c++11,foreach,C++,List,C++11,Foreach,我是C/C++编程新手,但我已经用C#编程1.5年了。我喜欢C++,我喜欢列表类,所以我想把C++中的列表类作为一个练习来做。 List<int> ls; int whatever = 123; ls.Add(1); ls.Add(235445); ls.Add(whatever); 这显然不适用于我的列表实现。我想我可以做一些宏魔术,但这感觉像一个巨大的黑客。事实上,最让我困扰的是通过这样的类型: #define foreach(type, var, list)\ int _i_

我是C/C++编程新手,但我已经用C#编程1.5年了。我喜欢C++,我喜欢列表类,所以我想把C++中的列表类作为一个练习来做。
List<int> ls;
int whatever = 123;
ls.Add(1);
ls.Add(235445);
ls.Add(whatever);
这显然不适用于我的列表实现。我想我可以做一些宏魔术,但这感觉像一个巨大的黑客。事实上,最让我困扰的是通过这样的类型:

#define foreach(type, var, list)\
int _i_ = 0;\
##type var;\
for (_i_ = 0, var=list[_i_]; _i_<list.Length();_i_++,var=list[_i_]) 

foreach(int,i,ls){
    doWork(i);
}
#定义foreach(类型、变量、列表)\
int(i)=0 ;\
##类型var\

对于(i i= 0,var =列表[Aii];S.Ii

语法智能提示不是C++,或者是一些MSVC扩展。 C++11具有遍历容器元素的功能。您需要实现

begin()
end()
类的成员函数,该函数将分别将迭代器返回到第一个元素和最后一个元素。当然,这意味着您也需要实现适合您的类的迭代器。如果您真的想走这条路,您可能想看看;它减少了您自己实现迭代器的许多痛苦

之后,您将能够编写以下内容:

for( auto const& l : ls ) {
  // do something with l
}


另外,由于您是C++的新手,所以我想知道标准库有好几类。

< P>首先,<代码> C++ >代码>中的<<代码>循环的<代码>与C><代码>不同(也称为<<代码>范围为循环< /COD>),其形式为:

for(<type> <name> : <collection>) { ... }
在封面下,这有效地使用了
begin()
end()
成员函数,它们返回迭代器。因此,为了允许自定义类为每个
循环使用
,您需要提供
begin()
end()
函数。这些函数通常重载,返回
迭代器或
常量迭代器。实现迭代器可能很棘手,尽管使用类似向量的类并不太难

template <typename T>
struct List
{
    T* store;
    std::size_t size;
    typedef T* iterator;
    typedef const T* const_iterator;

    ....

    iterator begin() { return &store[0]; }
    const_iterator begin() const { return &store[0]; }
    iterator end() { return &store[size]; }
    const_iterator end() const { return &store[size]; }

    ...
 };
模板
结构列表
{
T*商店;
标准:大小;
typedef T*迭代器;
typedef常量T*常量迭代器;
....
迭代器begin(){return&store[0];}
常量迭代器begin()常量{return&store[0];}
迭代器end(){return&store[size];}
常量迭代器end()常量{return&store[size];}
...
};

实现这些功能后,您可以像上面那样使用基于范围的循环。

C++在其语法中没有每个循环的
功能。您必须使用C++11或使用模板函数

#包括
#包括
#包括
结构和{
Sum(){Sum=0;}
void运算符()(int n){sum+=n;}
整数和;
};
int main()
{
std::向量nums{3,4,2,9,15,267};

std::cout正如@yngum所建议的,通过在集合上定义
begin()
end()
方法来返回自定义迭代器,您可以让每个
扩展的VC++
处理任意集合类型。您的迭代器反过来必须实现必要的接口(解引用运算符、增量运算符等)。我这样做是为了包装遗留代码的所有MFC集合类。这是一项工作,但可以完成。

iterable
iterable
类型。 那么为了

for (Type x : iterable)
编译时,必须有名为
Type
IType
的类型,并且必须有函数

IType Iterable::begin()
IType Iterable::end()
IType
必须提供以下功能

Type operator*()
void operator++()
bool operator!=(IType)

整个结构对于这样的东西来说是非常复杂的语法

for (IType it = iterable.begin(); it != iterable.end(); ++it) {
    Type x = *it;
    ...
}
如果不使用
类型
,则可以使用任何兼容类型(如
常量类型
类型&
),这将产生预期的影响(常量、引用而非副本等)

由于整个扩展是按语法进行的,因此您还可以稍微更改运算符的声明,例如,让*它返回一个引用或让!=根据需要获取一个
常量IType&rhs

请注意,如果
*表单不返回引用,则不能使用
for(Type&x:iterable)
表单(但如果它返回引用,也可以使用复制版本)

还请注意,
operator++()
定义了
++
运算符的前缀版本——但是,除非您明确定义后缀
++
,否则它也将用作后缀运算符。如果您只提供后缀
++
,则不会编译ranged for,顺便说一句,它可以声明为
operator++(int)
(伪int参数)


最简单的工作示例:

#include <stdio.h>
typedef int Type;

struct IType {
    Type* p;
    IType(Type* p) : p(p) {}
    bool operator!=(IType rhs) {return p != rhs.p;}
    Type& operator*() {return *p;}
    void operator++() {++p;}
};

const int SIZE = 10;
struct Iterable {
    Type data[SIZE];

    IType begin() {return IType(data); }
    IType end() {return IType(data + SIZE);}
};

Iterable iterable;

int main() {
    int i = 0;
    for (Type& x : iterable) {
        x = i++;
    }
    for (Type x : iterable) {
        printf("%d", x);
    }
}

可以用以下宏(

)伪造每个(例如,对于旧C++编译器)的范围
 #define ln(l, x) x##l // creates unique labels
 #define l(x,y)  ln(x,y)
 #define for_each(T,x,iterable) for (bool _run = true;_run;_run = false) for (auto it = iterable.begin(); it != iterable.end(); ++it)\
     if (1) {\
         _run = true; goto l(__LINE__,body); l(__LINE__,cont): _run = true; continue; l(__LINE__,finish): break;\
         } else\
            while (1)   \
                if (1) {\
                    if (!_run) goto l(__LINE__,cont);/* we reach here if the block terminated normally/via continue */   \
                    goto l(__LINE__,finish);/* we reach here if the block terminated by break */\
                }   \
                else\
                l(__LINE__,body): for (T x = *it;_run;_run=false) /* block following the expanded macro */                         

 int main() {
     int i = 0;
     for_each(Type&, x, iterable) {
         i++;
         if (i > 5) break;
         x = i;
     }
     for_each(Type, x, iterable) {
         printf("%d", x);
     }
     while (1);
 }
(如果编译器甚至没有auto,则使用declspec或pass IType)

输出:

 1234500000
正如您所看到的,
continue
break
由于其复杂的构造,可以使用它。
有关创建自定义控件结构的更多C预处理器黑客攻击,请参阅。

您可以编写
begin()
end()
成员函数和迭代器类型,使您的类与foreach兼容。您好,您的答案也很好,但遗憾的是,我无法接受2个答案。感谢您提供的链接:D@RicardoPieper请注意,基于范围的for循环仅在最新版本的visual studio(2012)中可用。所以它不会在任何其他编译器/IDE中编译?@RicardoPieper它会在过去几年的任何版本的Clang或gcc中编译(我认为gcc是4.7以上,不确定Clang版本).好的,这对我来说已经足够了,因为我使用VS2012进行编程。我成功地实现了迭代器,非常简单。我认为答案并不完整。您隐式地假设List::iterator具有一些功能(在本例中,您是免费的,因为迭代器是指针。这不是一般情况).迭代器类型的假设是什么?它是运算符++和运算符==。还有其他吗?
#include <stdio.h>
typedef int Type;

struct IType {
    Type* p;
    IType(Type* p) : p(p) {}
    bool operator!=(IType rhs) {return p != rhs.p;}
    Type& operator*() {return *p;}
    void operator++() {++p;}
};

const int SIZE = 10;
struct Iterable {
    Type data[SIZE];

    IType begin() {return IType(data); }
    IType end() {return IType(data + SIZE);}
};

Iterable iterable;

int main() {
    int i = 0;
    for (Type& x : iterable) {
        x = i++;
    }
    for (Type x : iterable) {
        printf("%d", x);
    }
}
0123456789
 #define ln(l, x) x##l // creates unique labels
 #define l(x,y)  ln(x,y)
 #define for_each(T,x,iterable) for (bool _run = true;_run;_run = false) for (auto it = iterable.begin(); it != iterable.end(); ++it)\
     if (1) {\
         _run = true; goto l(__LINE__,body); l(__LINE__,cont): _run = true; continue; l(__LINE__,finish): break;\
         } else\
            while (1)   \
                if (1) {\
                    if (!_run) goto l(__LINE__,cont);/* we reach here if the block terminated normally/via continue */   \
                    goto l(__LINE__,finish);/* we reach here if the block terminated by break */\
                }   \
                else\
                l(__LINE__,body): for (T x = *it;_run;_run=false) /* block following the expanded macro */                         

 int main() {
     int i = 0;
     for_each(Type&, x, iterable) {
         i++;
         if (i > 5) break;
         x = i;
     }
     for_each(Type, x, iterable) {
         printf("%d", x);
     }
     while (1);
 }
 1234500000