Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/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++ 我可以从基于for循环的范围内获取项的索引吗?_C++_Loops_C++11_Indexing_Range - Fatal编程技术网

C++ 我可以从基于for循环的范围内获取项的索引吗?

C++ 我可以从基于for循环的范围内获取项的索引吗?,c++,loops,c++11,indexing,range,C++,Loops,C++11,Indexing,Range,我定义了一组指针,如下所示: std::deque<BoardSquare *> mydeque; 是否可以从基于for循环的范围内获取项目的索引?不,不可能(至少不以合理的方式)。当您确实需要索引时,可能根本不应该使用基于范围的for循环,而是使用一个好的旧迭代器或基于索引的for循环: // non-idiomatic index-iteration, random access containers only for(std::size_t i=0; i<mydeque

我定义了一组指针,如下所示:

std::deque<BoardSquare *> mydeque;
是否可以从基于for循环的范围内获取项目的索引?

不,不可能(至少不以合理的方式)。当您确实需要索引时,可能根本不应该使用基于范围的for循环,而是使用一个好的旧迭代器或基于索引的for循环:

// non-idiomatic index-iteration, random access containers only
for(std::size_t i=0; i<mydeque.size(); ++i)
    mydeque[i];

// awfully ugly additional iteration variable, yet generic and fast
std::size_t i = 0;
for(auto iter=mydeque.begin(); iter!=mydeque.end(); ++iter,++i)
    *iter;

// idiomatic and generic, yet slow for non-random access containers
for(auto iter=mydeque.begin(); iter!=mydeque.end(); ++iter)
{
    auto i = std::distance(mydeque.begin(), iter);
    *iter;
}
//非惯用索引迭代,仅随机访问容器

对于(std::size\u t i=0;i您需要添加一个额外的变量来跟踪索引,复制(不可访问)由基于范围的循环使用的迭代器。您需要确保在每次迭代中正确初始化和递增迭代器,尤其要注意,如果有人向循环中添加
continue
语句,迭代器不会出错


使用索引(或迭代器,您可以在需要时从中计算索引)作为常规
for
循环的迭代变量将更简单、更不容易出错。

我提出了一个解决方案,或者说是一个实验性解决方案。下面是您将如何使用它:

for(auto item : make_indexable(v))
{
      //std::get<0>(item) is the index
      //std::get<1>(item) is the object
}


请注意,此解决方案并不完美,因为它不适用于临时容器和常量容器(以及常量对象的容器)。此外,现在,即使您编写
auto-item
,而不是
auto&item
(事实上,您无法编写
auto&item
),底层对象也将作为引用返回但是我认为这些问题可以通过更多的努力和仔细的设计来解决。毕竟,这只是一个基本思想的演示。

除了@ChristianRau给出的优秀答案显示了获取循环索引的首选方法之外,还有一种方法可以从范围for循环中获取索引,但前提是使用
std::vector
,因为它是保证内存中元素连续性的唯一容器

#include <deque>
#include <vector>
#include <iostream>

int main() 
{
    auto v = std::vector<int> { 0, 1, 2, 3 };
    auto d = std::vector<int*> { &v[0], &v[1], &v[2], &v[3] }; // NOT: std::deque

    for (auto ptr: d)
    {
        // assumes element contiguity, only guaranteed for std::vector!!
        auto const i = std::distance(&d[0], &ptr);
        std::cout << *(d[i]) << "\n";
    }
}
#包括
#包括
#包括
int main()
{
autov=std::向量{0,1,2,3};
auto d=std::vector{&v[0]、&v[1]、&v[2]、&v[3]};//NOT:std::deque
用于(自动ptr:d)
{
//假设元素连续,仅保证std::vector!!
自动常数i=std::距离(&d[0],&ptr);

std::cout如果需要索引,可能不应该使用基于范围的for循环。@wlyles:这是从索引中获取项,而不是从项中获取索引。@BeeBand:“糟糕”是需要一个额外的变量来跟踪索引,使用它(或迭代器)会更简单作为旧式的
for
循环中的循环变量。@BeeBand或只是可能注释upvotes是按预期方式工作的,而人们之所以向上投票是因为它是一个好的注释。你会感到恼火,因为你的问题的答案是,不要一开始就这样做?如果你执意要使用基于范围的方法对于循环,请继续执行Nawaz发布的操作。@BeeBand这就是为什么它只是一个注释而不是一个答案。看看我的解决方案。我想听听你对此的评论。查看我的答案,了解获取循环范围内索引的肮脏方法。好吧,当按引用而不是按值获取元素时,它更容易(但同样肮脏):
for(auto&&b:v)auto i=&b-v.data();
,不需要额外的向量。好的,您必须记住引用,但是在您的版本中,您仍然需要迭代一个完全不同的容器(这证明了这个问题是否仍然是基于相同范围的for循环)。仍然是有趣的方法。
#include <tuple>
#include <functional>

template<typename C>
struct indexed_container
{
    struct indexed_iterator
    {
        typedef typename C::value_type value_type;
        typedef std::tuple<size_t, std::reference_wrapper<value_type>> tuple_type;

        typename C::iterator _it;
        size_t _index;

        indexed_iterator(typename C::iterator it) : _it(it), _index(0) {}

        indexed_iterator& operator++()
        {
            ++_it;
            ++_index;
            return *this;
        }
        bool operator == (indexed_iterator const & other)
        {
            return _it == other._it;
        }
        bool operator != (indexed_iterator const & other)
        {
            return _it != other._it;
        }
        tuple_type operator*()
        {
            return std::make_tuple(_index, std::ref(*_it));
        }
    };

    indexed_container(C & c) : _c(c) {}

    indexed_iterator begin()
    {
        return indexed_iterator(_c.begin());
    }
    indexed_iterator end()
    {
        return indexed_iterator(_c.end());
    }
private:
    C & _c;
};

template<typename C>
auto make_indexable(C & c) -> indexed_container<C>
{
    return indexed_container<C>(c); 
}
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{1,2,3};
    for(auto item : make_indexable(v))
    {
        std::cout << std::get<0>(item) << " => " << std::get<1>(item) << std::endl;

        std::get<1>(item) *= 10; //modify value!
    }
    std::cout << "\nModified\n";
    for(auto item : make_indexable(v))
    {
        std::cout << std::get<0>(item) << " => " << std::get<1>(item) << std::endl;
    }
}
0 => 1
1 => 2
2 => 3

Modified
0 => 10
1 => 20
2 => 30
#include <deque>
#include <vector>
#include <iostream>

int main() 
{
    auto v = std::vector<int> { 0, 1, 2, 3 };
    auto d = std::vector<int*> { &v[0], &v[1], &v[2], &v[3] }; // NOT: std::deque

    for (auto ptr: d)
    {
        // assumes element contiguity, only guaranteed for std::vector!!
        auto const i = std::distance(&d[0], &ptr);
        std::cout << *(d[i]) << "\n";
    }
}