0

我真的很喜欢 C++11 及更高版本支持的基于 Ranged-based-for-loop。我想出于某种理解的原因来模拟它。这是一个例子:

// 1
//#define ranged_for(X, T) \
//  for (std::vector<int>::iterator beg{ T.begin() },\
//      end{ T.end() }; beg != end; X = *beg, ++beg)\

// 2
//#define ranged_for(X, T) \
//  for (std::vector<int>::iterator beg{ T.begin() },\
//      end{ T.end() }; beg != end; ++beg, X = *beg)\

// 3
#define ranged_for(X, T) \
    for (std::vector<int>::iterator beg{ T.begin() },\
        end{ T.end() }; beg != end; ++beg)\
            X = *beg, 



int main(){
    std::vector<int> data{75, 435, 6578, 92, 123};

    auto i{ 0 };
    ranged_for(i, data)
        std::cout << i << std::endl;

    std::cout << std::endl;
    std::cin.get();
    return 0;
}

正如您在上面看到的,第一个宏没有得到第一个元素75,而是值0,最后一个不存在。那是因为我猜在我的 main 中,我x在将其分配到循环的后迭代部分之前打印。

  • 第二个宏使程序崩溃,因为我认为取消引用最后一个节点(哨兵节点)。

  • 第三个工作正常,但正如您在宏扩展后看到的那样,我会得到:

    i = *beg, std::cout << i << std::endl;
    

这是因为上面的行被视为单个语句。有没有更好的方法和解释。谢谢各位好兄弟!。

4

2 回答 2

1

为什么你这么反对 C++ ranged based for 循环?

int i;
ranged_for(i, data)
    // ...

对比

for(int i : data)

i到目前为止,您需要预先声明。您不能以这种方式使用引用!现在让我们想象一下我们设法让它变得更聪明:

ranged_for(int& i, data)

对比

for(int& i : data)

你得到了什么?使用逗号而不是冒号???老实说,这不值得努力。一个更有趣的场景需要考虑:

auto i = data.end();
for(auto j = data.begin(); j != data.end(); ++j)
{
    if(someCondition)
        i = j;
}
if(i != data.end())
{
    // ...
}

好的,这已经相当罕见了。在许多情况下,如果不是大多数情况下,您可以将外部 if 的主体移动到内部的主体中,并在最后添加一条break指令。在这少数情况下,你仍然不能这样做——好吧,那么我会接受显式迭代器循环——写起来并不那么繁重……

于 2018-12-28T22:04:46.787 回答
1

这应该适用于单行和多行范围:

#define ranged_for(X, T) \
    for(auto it=std::begin(T); it!=std::end(T) && (X=*it,true); ++it)

或者可以用来自动推断类型的版本X应该是,但它需要一个额外的宏:

#define ranged_for(X, T) \
    {decltype(T)::value_type X; for(auto it=std::begin(T); it!=std::end(T) && (X=*it,true); ++it) {

#define range_end }}

int main(){
    std::vector<int> data{75, 435, 6578, 92, 123};

    ranged_for(i, data)
        std::cout << i << std::endl;
    range_end
}
于 2018-12-28T22:04:58.483 回答