[英]How do I combine two template functions that have the same code?
我正在尝试创建一个模板来轻松输出容器,以便调试代码。 我希望能够做到
int a = 3;
pair<int,int> b = {2,3};
vector<int> c = {1,2,3,4};
map<int,int> m;
m[2] = 3;
m[3] = 4;
dbg(a,b,c,m);
OUTPUT:
[a,b,c,m] = [ 3 , (2,3) , {1,2,3,4} , {(2,3),(3,4)} ]
到目前为止,我有这个:
#define dbg(x...) cout << "[" << #x << "] = [ "; _dbg(x); cout << "]"
template <typename T> void _dbg(T t)
{
cout << t << " ";
}
template<typename T, typename... Args>
void _dbg(T t, Args... args) // recursive variadic function
{
cout << t << " , ";
_dbg(args...);
}
template <typename T, typename V>
ostream& operator<<(ostream& os, const pair<T, V> p)
{
cout << "(" << p.first << "," << p.second << ")";
}
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& dt)
{
cout << "{";
auto preEnd = dt.end();
preEnd--;
for (auto bgn = dt.begin(); bgn != preEnd; bgn++)
cout << *bgn << ",";
cout << *preEnd << "}";
return os;
}
template <typename T>
ostream& operator<<(ostream& os, const set<T>& dt)
{
cout << "{";
auto preEnd = dt.end();
preEnd--;
for (auto bgn = dt.begin(); bgn != preEnd; bgn++)
cout << *bgn << ",";
cout << *preEnd << "}";
return os;
}
template <typename T, typename V>
ostream& operator<<(ostream& os, const map<T, V>& dt)
{
cout << "{";
auto preEnd = dt.end();
preEnd--;
for (auto bgn = dt.begin(); bgn != preEnd; bgn++)
cout << *bgn << ",";
cout << *preEnd << "}";
return os;
}
而且效果很好! 只是我不想为每个容器类型定义一个函数,因为它们都具有相同的主体(谈论最后 3 个函数)。 我试过类似的东西
template<typename C, typename T>
ostream& operator<<(ostream& os, const C<T>& dt)
但我得到了
error: C is not a template
我试过
template<typename C>
ostream& operator<< (ostream& os, const C& dt)
并得到
error: no match for 'operator<<' (operand types are
'std::ostream {aka std::basic_ostream<char>}' and 'std::set<int>')|
那么我如何只有一个处理任何容器的通用函数(例如,一个是template<typename T> vector<T>
,另一个是set<T>
??)
我如何只有一个处理任何容器的通用函数?
正如@Const在评论部分已经提到的那样,您可以提供一个模板化的operator<<
重载,它具有模板模板参数,以便它可以接受您选择的容器,其范围将传递给辅助函数(即下面的print_helper
示例)打印元素。 这要求容器的元素具有operator<<
定义; 就像您为std::pair
类型提供了重载一样。
template <typename Iterator>
std::ostream& print_helper(std::ostream& os
, Iterator start, const Iterator end) noexcept
{
for (; start != end; ++start) os << *start;
return os << '\n';
}
// template template parameter
template <template<typename Type, typename... Rest> class Conatiner, typename Type, typename... Rest>
std::ostream& operator<<(std::ostream& os
, const Conatiner<Type, Rest...>& container) noexcept
{
// pass the ranges to helper function
return print_helper(os, std::begin(container), std::end(container));
}
如果您有 C++ 20,那么通过将模板约束在概念上会更容易。
Nb std::string
和char[]
都是满足std::ranges::range
,但我们不希望它们使用我们的模板
template <typename T>
concept non_string_range = std::ranges::range<T> && !std::is_same_v<std::ranges::range_value_t<T>, char>;
template <non_string_range T>
std::ostream& operator<<(std::ostream& os, const T & range) {
std::cout << "{";
std::string prefix;
for (auto & elem : range) {
std::cout << prefix << elem;
prefix = ",";
}
std::cout << "}";
return os;
}
在 C++20 之前,你可以用 trait 和std::enable_if
做类似的事情
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.