2010-01-01 97 views
3

重载的for_each我使用一个typedef定义容器的类型在我的程序,这样我可以使用正常的STL容器和STXXL容器之间容易地切换,沿着线:特定迭代器类型

typedef stxxl:vector<Data> MyContainer; 

typedef std:vector<Data> MyContainer; 

一个困难是,STXXL提供的std::for_each一个特殊版本,stxxl::for_each即与STXXL容器的使用进行了优化。当MyContainer的typedeffed为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我的版本被调用?

更新:我得到的第二个想法现在的工作,张贴。问题是我包含了错误的文件(哎哟......)。但第一个问题仍然存在:对这个问题的首选解决方案是什么?是否可以重载std :: for_each,因为std命名空间不适用于凡人?

+0

我永远不会记住你被允许注入std namespacem的规则,我打赌大多数其他人也不能。所以我宁愿选择非侵入性解决方案。 – 2010-01-01 16:50:41

回答

6

您可以在STD(17.4.3.1)专门的模板,但你不能添加过载。你的定义是一个重载,而不是标准的for_each模板的专门化,在任何情况下,函数都不能部分专用。所以没有定义将任何定义放在名字空间std中,它可以做你想做的事。

ADL应该使这项工作顺利,没有任何需要,虽然。我假设stxxl迭代器位于stxxl命名空间中,因此for_each(first, last, f, 4);应该调用stxxl::for_each。如果你想std::for_each,你完全有资格名称,当你打电话给它。

+0

好点,没有意识到。谢谢! – 2010-01-01 17:21:19

1

的std :: for_each的是公众有据可查的算法功能,我不认为我伤口喜欢它,如果某些库我使用善有善报改变它; - 。也许我的程序的其他部分需要良好的旧的for_each

所以我会不会打破这个接口和树叶的std :: for_each的,因为它是一种解决方案。

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。这真的很有启发性,有点可怕。如果你只使用一些类型/函数组合,你可以编写一个漂亮的宏(gasp)来为你自动化。

你也可以使用ADL来解决这个问题,前提是stxxl的东西都不使用typedef公开std的迭代器。我相信这通常是今天的首选解决方案。

我会在for_each附近添加自己的包装,将其转发给相应的包装并称之为完成。这不是最优雅的,但它现在可以工作,并且不依靠任何魔法来实现它。

+0

这不仅仅是你的意见,它是无法使用的;部分*功能*模板专业化不存在,虽然这是TC试图使用的功能。 – 2010-01-01 17:30:22

+0

没有这样的事情,专业化或部分专业化的功能 - 只有重载(它可以看起来像你认为的模板类专业化) – 2010-01-01 17:31:40

+0

“前提是没有任何stxxl的东西只是暴露了std的迭代器使用typedef” 。如果是这样,那么获取std :: for_each可能没问题。我们被告知stxxl :: for_each是stxxl容器的优化。因此,如果某个stxxl迭代器实际上是一个std迭代器,那么我会打赌,无论哪种优化适用于其他stxxl迭代器,都不适用于那个。 – 2010-01-01 17:37:26

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); 
} 

我试过了,但未能使它与迭代器一起工作。

+0

你在这里超载Ufor_each,而不是部分专精 – 2010-01-01 17:34:16

1

总结:

  • 没有这样的东西的功能部分专业化。只使用特定类型重载该函数
  • 通常禁止在命名空间中放入东西std
  • 您真正想要的是将for_each的重载放入特定迭代器类型(“旁边”)的名称空间中'超载。这可以确保ADL能够找到它。