2014-12-06 201 views
3

如何在容器和类型上定义一个函数模板?作为模板参数的模板类

例如,过载操作者插入到流的矢量,列表或,前向迭代容器中的所有元素:

using namespace std; 

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


//... 
//...the second argument is a container template-ed on type T 
//... 
template <typename T,template <typename U> class C> 
ostream& 
operator<< 
    (ostream& p_os,const C<T>& p_c) 
{ 
    for(typename C<typename T>::const_iterator cit=p_c.begin();cit!=p_c.end();++cit) 
    { 
    p_os.operator<<(*cit); 
    } 
    return p_os; 
} 

int 
main 
() 
{ 
    vector<int> v; 
    cout << v << endl; 
    list<int> l; 
    cout << l << endl; 
    return 0; 
} 

这并不对于g ++ 4.9编译。哪里不对?它是如何完成的?

回答

1

为什么不只是传递容器类型作为模板参数,并从中找出元素类型?在你的示例代码,你甚至不需要元素类型:

template <typename C> 
ostream& 
operator<< 
    (ostream& p_os,const C& p_c) 
{ 
    typedef typename C::value_type element_type; // if needed 
    for(typename C::const_iterator cit=p_c.begin();cit!=p_c.end();++cit) 
    { 
    p_os.operator<<(*cit); 
    } 
    return p_os; 
} 

(虽然它可能是不明智的使用像这样的全局函数没有一些enable_if挂羊头卖狗肉,因为否则将会匹配任何参数)。

编辑:例如,你可以尝试用一个嵌套value_type(所有容器都)限制这类:

template <typename C, typename T = typename C::value_type> 
ostream& 
operator<< 
    (ostream& p_os,const C& p_c) 
+0

这种方法做我想要的。我已经扩展了这个功能来支持流式处理所有的容器类型 – silvermangb 2014-12-07 03:26:52

+0

“(尽管在没有某些enable_if技巧的情况下将它用于这样的全局函数可能是不明智的,因为它会以其他方式匹配任何参数。)”我尝试使用逗号分隔容器的条目,但编译器试图使用该函数来传输字符串。如何通过enable_if来避免这种情况? – silvermangb 2014-12-07 05:42:36

+0

请参阅编辑(实际上并未使用'enable_if')。对于更复杂,更强大的解决方案,请参阅http://stackoverflow.com/questions/9242209/is-container-trait-fails-on-stdset-sfinae-issue。 – 2014-12-07 10:30:29

1

std::vector是具有模板类型参数的类模板:

template <class T, class Alloc = allocator<T> > 
class vector; 

为了使您的函数std::vector(和其他两个参数的类模板),则可以使用如下的定义:

template <typename T, typename A, template <typename, typename> class C> 
//     ~~~~~~~~~^      ~~~~~~~^ 
ostream& operator<<(ostream& p_os, const C<T,A>& p_c) 
//           ^^ 
{ 
    for(typename C<T,A>::const_iterator cit=p_c.begin();cit!=p_c.end();++cit) 
    { 
    p_os.operator<<(*cit); 
    } 
    return p_os; 
} 

或者:

template <typename T, template <typename...> class C> 
ostream& operator<<(ostream& p_os, const C<T>& p_c); 
+0

'vector'具有*至少*两个模板参数 - 一个实现可以添加更多,只要它们具有默认值。所以第一个版本是不可移植的。 – 2014-12-06 21:28:25

+0

@AlanStokes我不相信你,标准在哪里说的? – 2014-12-06 21:31:21

+0

我的歉意,这段“常识”原来并非如此。这是建议,但被拒绝:http://stackoverflow.com/questions/1469743/standard-library-containers-with-additional-optional-template-parameters – 2014-12-06 21:37:50

0

艾伦·斯托克斯方法效果。下面的代码可以流式传输任何容器。我只需要为地图添加插入运算符

using namespace std; 

#include <iostream> 

#include <vector> 
#include <list> 
#include <forward_list> 
#include <set> 
#include <deque> 
#include <array> 
#include <map> 
#include <unordered_map> 

//... 
//...needed for map types which are (key,value) pairs. 
//... 
template <typename K,typename V> 
ostream& 
operator<< 
    (ostream& p_os,const pair<const K,V>& p_v) 
{ 
    std::operator<<(p_os,'('); 
    p_os << p_v.first; 
    std::operator<<(p_os,','); 
    p_os << p_v.second; 
    std::operator<<(p_os,')'); 
    return p_os; 
} 

template <typename C, typename T = typename C::iterator> 
ostream& 
operator<< 
    (ostream& p_os,const C& p_c) 
{ 
    for(typename C::const_iterator cit=p_c.begin();cit!=p_c.end();++cit) 
    { 
    typename C::value_type v = *cit; 
    p_os << v; 
    std::operator<<(p_os,","); 
    } 
    return p_os; 
} 

int 
main 
() 
{ 
    vector<int> v; 
    for(int i=0;i<4;++i) 
    { 
    v.push_back(i); 
    } 
    cout << v << endl; 
    list<int> l; 
    for(int i=0;i<4;++i) 
    { 
    l.push_back(i); 
    } 
    cout << l << endl; 
    forward_list<int> fl = {0,1,2,3}; 
    cout << fl << endl; 
    set<int> s; 
    for(int i=0;i<4;++i) 
    { 
    s.insert(i); 
    } 
    cout << s << endl; 
    deque<int> d; 
    for(int i=0;i<4;++i) 
    { 
    d.push_back(i); 
    } 
    cout << d << endl; 
    array<int,4> a = {0,1,2,3}; 
    cout << a << endl; 
    unordered_map<int,int> um; 
    for(int i=0;i<4;++i) 
    { 
    um[i] = i; 
    } 
    cout << um << endl; 
    map<int,int> m; 
    for(int i=0;i<4;++i) 
    { 
    m[i] = i; 
    } 
    cout << m << endl; 
    return 0; 
} 
+0

仍然不完全正确。导致运算符<< for std :: string的歧义。 – silvermangb 2014-12-08 01:43:09

+0

好吧,'string'是一个容器,所以它应该匹配它。 – 2014-12-08 09:20:39

+0

不过,我想为字符串解决方法。序列化任何容器操作符<<而不阻止字符串或其他对象被序列化是我长期以来想要的。 – silvermangb 2014-12-09 19:26:48

相关问题