C++ C++;11:使用单范围循环有效地迭代矩阵?

C++ C++;11:使用单范围循环有效地迭代矩阵?,c++,gcc,c++11,C++,Gcc,C++11,(对于具体的编译器/平台上下文,采用x86_64上的GCC 4.7和Ubuntu 12.04) 给定一些函数f: void f(int x, int y); int nx = ...; int ny = ...; 迭代从(0,0)到(nx,ny)的每个值(x,y)的一种方法是: 编译为代码Q2 写g是否可能使Q2和Q1一样有效?如果是,如何进行?如果没有,我们能得到的最接近的是什么 如果有帮助,您可以将“自动”更改为“自动”或“自动” 如果有帮助,您还可以将它.x更改为it.x(),将它.y

(对于具体的编译器/平台上下文,采用x86_64上的GCC 4.7和Ubuntu 12.04)

给定一些函数f:

void f(int x, int y);

int nx = ...;
int ny = ...;
迭代从(0,0)到(nx,ny)的每个值(x,y)的一种方法是:

编译为代码Q2

写g是否可能使Q2和Q1一样有效?如果是,如何进行?如果没有,我们能得到的最接近的是什么

如果有帮助,您可以将“自动”更改为“自动”或“自动”

如果有帮助,您还可以将它.x更改为it.x(),将它.y更改为it.y()

(回想一下,基于范围的for扩展只是您选择的一种类似迭代器的类型:)

写g是否可能使Q2和Q1一样有效?如果是,如何进行?如果没有,我们能得到的最接近的是什么

当然这是可能的,您只需要定义迭代器,迭代器的增量与
for
循环的增量相同。从我的头顶:

class matrix_iterator
{
public:
    ...

    matrix_iterator& operator++()
    {
        if( ++y >= ny )
        {
            ++x;
            y = 0;
        }

        return *this;
    }

private:
    int nx, ny;
    int x, y;
};

此代码具有您想要的功能。我还没有验证它,但我怀疑它将产生与原始循环几乎相同的机器代码(在优化编译中)

struct iter {
    int x, y, ny;
    iter(int x, int y, int ny) : x(x), y(y), ny(ny) {}
    iter &operator++ () {
        if (++y >= ny)
        {
            y = 0;
            ++x;
        }
        return *this;
    }
    bool operator != (iter const &rhs) const {
        return y != rhs.y || x != rhs.x;
    }
};

struct container {
    iter endit;
    container(int nx, int ny) : endit(nx, ny, ny) {}
    iter begin() const { return iter(0,0,endit.ny); }
    iter const &end() const { return endit; }
};

container g(Z const &z) { return container(z.nx, z.ny); }

for ( auto it : g(Z) )
    f(it.x, it.y);

删除了
[c]
标记,在c中没有范围,同样的
auto
作为推断声明类型。而且,这并不是Linux特有的,所以我也删除了这个标记。虽然您可能能够获得接近原始循环的性能,但它的速度可能至少会稍微慢一些(更复杂的代码意味着编译器更难进行优化,并且会有额外的对象等等。简单的双循环有什么问题?(还要注意最简单的简单方法:
for(int i=0;i
——再次稍微慢于original@DavidRodríguez dribeas:实际上,mod和div通常是用IDIV指令实现的,这比增量或比较慢大约100倍。@AndrewTomazos Dethomling:再说一遍,“f”的成本是多少?这个问题相当荒谬(将常见的简单循环更改为不常见的循环)并且您要求“相似的性能”。解决方案相对于整体操作的相对成本将使性能相似或不相似。如果
f
是两个循环,则没有解决方案在性能上相似(一个额外的循环可能会对整个循环产生巨大影响),但如果
f
需要几秒钟,则该循环的所有解决方案将具有类似的性能(1或100个循环不会对整个循环的成本产生影响)
container::begin
中的
ny
从何而来?使
endit
const使
container
无意义地不可复制。使其私有化和非常量化,
container
将具有完全相同的语义+可复制性。我不认为可复制性对于这个特定示例很重要,但我改变了它无论如何,对于非常量。我不认为这会更有效率。总的来说,您正在进行x*y*3比较:每个(x,y)在运算符!=中有2个,在运算符++中有1个.另一方面,最初的两个叠瓦循环只进行x*y比较。const成员使其不可赋值而不可复制。根据
f
的成本,迭代器的额外成本和对基于范围的for循环中的变量的复制可能是显而易见的——这并不是对解决方案的抱怨,但我不认为这个问题很有意义,两个答案都为一个简单的问题提供了一个复杂的解决方案:只需编写两个循环:)@David Rodríguez-dribeas:真的吗?你看过今天的编译器吗?他们可以并且确实优化了这类东西,这样生成的代码是等效的。我看过今天的编译器…效果不会很大,但是如果
f
是一个轻量级函数,它可能会有(小)影响。就像一个一般问题一样…
std::bind(&f,x)
在不同的实现中:用g++编译的boost::bind制作了4个
x
,g++4.7
std::bind制作了一个副本(我所期望的),VS2010是7,是7!!!是
x
的副本。我已经看到了编译器所做的事情,事实是,对于这样简单的事情,过分使用更复杂、更难维护且可能更昂贵的解决方案是没有意义的……只是说:)
class matrix_iterator
{
public:
    ...

    matrix_iterator& operator++()
    {
        if( ++y >= ny )
        {
            ++x;
            y = 0;
        }

        return *this;
    }

private:
    int nx, ny;
    int x, y;
};
struct iter {
    int x, y, ny;
    iter(int x, int y, int ny) : x(x), y(y), ny(ny) {}
    iter &operator++ () {
        if (++y >= ny)
        {
            y = 0;
            ++x;
        }
        return *this;
    }
    bool operator != (iter const &rhs) const {
        return y != rhs.y || x != rhs.x;
    }
};

struct container {
    iter endit;
    container(int nx, int ny) : endit(nx, ny, ny) {}
    iter begin() const { return iter(0,0,endit.ny); }
    iter const &end() const { return endit; }
};

container g(Z const &z) { return container(z.nx, z.ny); }

for ( auto it : g(Z) )
    f(it.x, it.y);