为特定迭代器类型重载for_each

时间:2010-01-01 16:28:42

标签: c++

我正在使用typedef在我的程序中定义容器的类型,这样我就可以在使用普通STL容器和STXXL容器之间轻松切换,如下所示:

typedef stxxl:vector<Data> MyContainer;

typedef std:vector<Data> MyContainer;

一个难点是STXXL提供了std::for_eachstxxl::for_each的特殊版本,该版本已针对STXXL容器进行了优化。当MyContainer的类型设置为stxxl::vector时,我更喜欢使用此功能。

一种解决方案是定义我自己的for_each函数,该函数调用正确的for_each函数,并在我想调用for_each时使用它。

我正在研究的另一个解决方案是重载/专门化std::foreach,以便在调用stxxl::for_each作为第一个和第二个参数时调用stxxl::vector<Data>::(const_)iterator

我无法获得第二个想法。我尝试了以下内容:

namespace std
{
    template <class UnaryFunction>
    UnaryFunction for_each(stxxl:vector<Data>::const_iterator first, 
        stxxl:vector<Data>::const_iterator last, UnaryFunction f)
    {
        stxxl::for_each(first, last, f, 4);
    }
}

与非const迭代器的类似函数一起使用。他们不会被召唤。

这个问题的首选解决方案是什么?如何让std::for_each stxxl::vector版本的{{1}}迭代器被调用?

更新:我发布了第二个想法。问题是我包含了错误的文件(哎呀......)。但问题仍然存在:这个问题的首选解决方案是什么?是否可以重载std :: for_each,因为std命名空间不适合凡人?

5 个答案:

答案 0 :(得分:6)

您可以在std(17.4.3.1)中专门化模板,但不能添加重载。您的定义是重载,而不是标准for_each模板的特殊化,并且在任何情况下,函数都不能部分专门化。所以在命名空间std中放置任何可能做你想做的事情的定义都是未定义的。

但是,ADL应该能够顺利完成这项工作,而不需要这样做。我假设stxxl迭代器在stxxl命名空间中,因此for_each(first, last, f, 4);应该调用stxxl::for_each。如果您需要std::for_each,则在致电时完全符合该名称。

答案 1 :(得分:2)

尽管我想说要注入std命名空间,但是Neil指出它真的是一个粘性的检票口。 related thread of std::swap指出了一些细节,就像现在臭名昭着的USENET discussion on the subject一样。

总而言之,允许您将名称注入std的唯一方法是,如果您可以完全专注它。所以,你可以写:

namespace std {
    template <>
    MyFunction for_each(stxxl::vector<Data>::const_iterator first,
                        stxxl::vector<Data>::const_iterator last,
                        MyFunction func)
    {
        return stxxl::for_each(first, last, func);
    }
}

对于容器和功能的每个组合,你完全符合规则。遗憾的是,标准的当前版本中不存在部分函数模板特化。如果你真的很好奇,请花一个晚上来阅读整个USENET post。这真的很有启发性,有点令人恐惧。如果你只使用一些类型/功能组合,你可以编写一个漂亮的宏(喘气)为你自动化。

您可以使用ADL来解决问题,前提是stxxl内容都不会使用typedef从std公开迭代器。我相信这通常是今天的首选解决方案。

我会在for_each周围添加你自己的包装器,然后转发到相应的包装器并调用它。这不是最优雅的,但它现在可以工作,不依赖任何魔法来实现它。

答案 2 :(得分:1)

std :: for_each是一个公开记录良好的算法函数,如果我正在使用的某些库改变它,我认为我不会喜欢它; - 。可能我的程序的其他部分需要好的旧的for_each

所以我会选择不破坏此接口的解决方案,并保留std :: for_each。

答案 3 :(得分:1)

总结:

  • 没有功能的部分特化。仅使用您的特定类型重载该功能
  • 一般禁止将东西放入命名空间std
  • 你真正想要的是将for_each的重载放在你正在重载的特定迭代器类型(“旁边”)的命名空间中。这可以确保ADL找到它。

答案 4 :(得分:0)

我不会尝试专门化std :: for_each() 特别是因为你想要的是部分专业化。

相反,我会编写一个使用std :: for_each()的函数,但是对stlxxl有一个特殊化。
我没有stlxxl所以我做了一些代码来证明我的意思。

#include <vector>
#include <list>
#include <algorithm>
#include <iostream>

//
// Normal version.
template<typename U,typename T,typename A,template<class I,class A> class C>
U Ufor_each(C<T,A>& cont,U const& f)
{
    std::cout << "NORMAL Start" << std::endl;
    return std::for_each(cont.begin(),cont.end(),f);
    return f;
}

// 
// Specialized version.
// You could write a specialized version for stlxxl::vector
template<typename U,typename T>
U Ufor_each(std::vector<T>& cont,U const& f)
{
    std::cout << "Vector Start" << std::endl;
    return std::for_each(cont.begin(),cont.end(),f);
}

struct X
{
    void operator()(int data) const
    {
        std::cout << "Item: " << data << std::endl;
    }
};

int main()
{
    std::vector<int>    vect;
    std::list<int>      list;

    vect.push_back(1);
    list.push_back(4);

    X                   x;
    Ufor_each(vect,x);
    Ufor_each(list,x);
}

我尝试但未能使用迭代器。