[英]How do I combine two template functions that have the same code?
I am trying to create a template for easily outputting containers, for the purpose of debugging code.我正在尝试创建一个模板来轻松输出容器,以便调试代码。 I would like to be able to do
我希望能够做到
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)} ]
So far I have this:到目前为止,我有这个:
#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;
}
And it works great!而且效果很好! It's just that I don't want to define a function for every single container type, when they all would have the same body (talking about the last 3 functions).
只是我不想为每个容器类型定义一个函数,因为它们都具有相同的主体(谈论最后 3 个函数)。 I tried something like
我试过类似的东西
template<typename C, typename T>
ostream& operator<<(ostream& os, const C<T>& dt)
But I got但我得到了
error: C is not a template
and I tried我试过
template<typename C>
ostream& operator<< (ostream& os, const C& dt)
And got并得到
error: no match for 'operator<<' (operand types are
'std::ostream {aka std::basic_ostream<char>}' and 'std::set<int>')|
So how do I just have one generic function that deals with any container (ex. one being template<typename T> vector<T>
, and the other set<T>
??)那么我如何只有一个处理任何容器的通用函数(例如,一个是
template<typename T> vector<T>
,另一个是set<T>
??)
How do I just have one generic function that deals with any container?
我如何只有一个处理任何容器的通用函数?
As @Const already mentioned in the comment section, you can provide a templated operator<<
overload which has template template parameter , so that it can accept the containers of your choice, whose ranges will be passed to a helper function (ie print_helper
in following example) to print the elements.正如@Const在评论部分已经提到的那样,您可以提供一个模板化的
operator<<
重载,它具有模板模板参数,以便它可以接受您选择的容器,其范围将传递给辅助函数(即下面的print_helper
示例)打印元素。 This required the elements of the container to have operator<<
defined;这要求容器的元素具有
operator<<
定义; like you have provided the overload for std::pair
type.就像您为
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));
}
This works for c++11 and here is ( the complete example code )这适用于c++11 ,这里是(完整的示例代码)
If you have C++ 20, this is made easier by having a template constrained on a concept.如果您有 C++ 20,那么通过将模板约束在概念上会更容易。
Nb std::string
and char[]
are both types that satisfy std::ranges::range
, but we don't want those to use our template 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;
}
Prior to C++20 you can do similar things with a trait and std::enable_if
在 C++20 之前,你可以用 trait 和
std::enable_if
做类似的事情
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.