我想用以下代码为operator<<
和std::list
重载std::vector
。但是这两个功能几乎相同。有什么办法可以将它们组合起来,即创建更通用的重载吗?
#include <iterator>
#include <iostream>
#include <vector>
#include <list>
template <typename T>
std::ostream &operator<<(std::ostream &out, const std::vector<T> &v)
{
if (!v.empty())
std::copy(v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
return out;
}
template <typename T>
std::ostream &operator<<(std::ostream &out, const std::list<T> &v)
{
if (!v.empty())
std::copy(v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
return out;
}
int main()
{
std::cout << std::vector<int>({1, 2, 3, 4}) << std::endl;
std::cout << std::list<int>({1, 2, 3, 4}) << std::endl;
return 0;
}
答案 0 :(得分:4)
您可以像以下示例中那样使用template with template arguments:
template <typename T, typename A, template <typename X, typename Y> class C>
std::ostream &operator<<(std::ostream &os, const C<T,A> &container)
{
if(!container.empty())
std::copy(container.begin(), container.end(), std::ostream_iterator<T>(os, " "));
return os;
}
int main() {
list<int> l{1,2,3,4,5};
vector<string> v{"one","two","three"};
cout<<l<<endl<<v;
return 0;
}
在线 demo 。
顺便说一句,您可以在this SO问题中找到使用模板模板的其他示例。
但是您必须小心使用这种结构:
备注: 如果要寻找通用解决方案,则最好考虑创建一个使用迭代器作为参数的适配器模板,然后编写该适配器的通用提取器。
答案 1 :(得分:2)
输入C ++ 20,并可能包含Concepts和Ranges,则可以大大简化您的问题的解决方案。
概念基本上是一个带有约束条件的模板参数,例如
// Taken from https://en.cppreference.com/w/cpp/experimental/constraints
template <typename T>
concept bool Integral = std::is_integral<T>::value;
template <Integral T> // Using concept Integral.
void foo(T i) { /* ... */ } // 'i' has to be integral, or compile time error.
现在,范围(简化)的概念符合接口(伪代码)的要求:
Range {
begin()
end()
}
使用它,可以编写如下内容:
template <Range T>
std::ostream& operator<<(std::ostream& out, T&& rng) {
std::copy(std::forward<T>(rng), std::make_ostream_joiner(out, ", "));
return out;
}
它仅适用于具有begin()
和end()
的任何内容,例如
std::cout << std::vector{1, 2, 3, 4, 5} << std::endl; // Ok
std::cout << std::list{1, 2, 3, 4, 5} << std::endl; // Ok
此外,请注意,我使用的是std::make_ostream_joiner
而不是std::ostream_iterator
。它利用了一个新的C ++ 20迭代器std::ostream_joiner
,该迭代器在每两个对象之间写入了分隔符,从而跳过了额外的尾部分隔符,即您将获得"1, 2, 3, 4, 5"
而不是"1, 2, 3, 4, 5, "
。
我们希望所有这些功能都可以纳入C ++ 20中:)
注意::给出的所有示例都是假设的C ++ 20代码,目前无法使用我所知道的任何发行版构建编译器进行编译。