2013-10-26 45 views
10

我想为所有具有基于范围基础的类实现漂亮打印,以支持超载< <。 (错误)代码是这样的。漂亮的打印所有具有基于范围基础的类支持循环支持

template<class C> ostream& operator<<(ostream& out, const C& v) { 
    for(auto x : v) out<<x<<' '; 
    return out; 
} 

的这里的问题是,这将与现有的< <重载冲突。有没有一种方法可以在模板中指定C必须支持ranged-for循环?

回答

11

由于基于范围的for循环需要begin(v)end(v)要与ADL(和std::是相关的命名空间)有效,您可以使用此:

namespace support_begin_end 
{ 
    // we use a special namespace (above) to 
    // contain the using directive for 'std': 
    using namespace std; 

    // the second parameter is only valid 
    // when begin(C()) and end(C()) are valid 
    template<typename C, 
     typename=decltype(begin(std::declval<C>()),end(std::declval<C>())) 
    > 
    struct impl 
    { 
     using type = void; // only here impl 
    }; 

    // explicitly disable conflicting types here 
    template<> 
    struct impl<std::string>; 
} 

// this uses the above to check for ::type, 
// which only exists if begin/end are valid 
// and there is no specialization to disable it 
// (like in the std::string case) 
template<class C,typename = typename supports_begin_end::impl<C>::type> 
std::ostream& operator<<(std::ostream& out, const C& v) { 
    for(auto x : v) out<<x<<' '; 
    return out; 
} 

Live example

还有其他类型的虽然,它适用于基于范围的循环。不知道你是否也需要检测它们。


这里有一个更新的live example检测两个容器/支持begin(v)/end(v)以及支持v.begin()/v.end()种类型。

+0

你介意解释一下这里发生的一些事情吗?会是可爱的谢谢! – lfxgroove

+0

@lfxgroove看看更新的答案是否有帮助。 –

+0

当然可以,谢谢你! – lfxgroove

6

SFINAE:

template<class C> 
auto operator<<(std::ostream& out, const C& v) -> decltype(v.begin(), v.end(), (out)) 
//           or -> decltype(std::begin(v), std::end(v), (out)) 
{ 
    for (auto x : v) 
     out << x << ' '; 
    return out; 
} 
4

A于所有的答案一般性评论:

使用

for (auto x : v) 

将复制出来的集合中的所有元素打印前,造成了很多对拷贝构造函数和析构函数的调用。你可能更好用

for (auto &x : v) 

作为你的循环。