我想通过重载<<来为所有具有ranged-base for for循环支持的类实现漂亮打印。 (错误的)代码是这样的。
template<class C> ostream& operator<<(ostream& out, const C& v) {
for(auto x : v) out<<x<<' ';
return out;
}
这里的问题是这会与现有的&lt;&lt;超载。有没有办法在模板中指定C必须支持ranged-base for loop?
答案 0 :(得分: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,可检测支持begin(v)
/ end(v)
的容器/类型以及支持v.begin()
/ v.end()
的类型。
答案 1 :(得分: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;
}
答案 2 :(得分:4)
对所有答案的一般性评论:
使用
for (auto x : v)
将在打印之前复制集合中的所有元素,从而导致对复制构造函数和析构函数的大量调用。
你可能会更好for (auto &x : v)
作为你的循环。