简体   繁体   English

如何组合具有相同代码的两个模板函数?

[英]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 and here is ( the complete example code )这适用于 ,这里是完整的示例代码

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::stringchar[]都是满足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.

相关问题 为什么两个函数具有相同的地址? - Why do two functions have the same address? 为什么必须在同一个翻译单元中声明模板类函数? - Why do template class functions have to be declared in the same translation unit? 如何合并两个字符串? - How do I combine two strings? 在C ++中,如何使同一个类的两个对象具有唯一的函数行为? - In c++, how can I make two objects of the same class have unique functions behaviour? 如何组合仅在声明的类型中有所不同的两个函数 - How can I combine two functions that differ only in the types declared 如何强制两个具有相同模板类型的函数参数? - How can I enforce two function parameters have the same template type? 如何将三角函数用于模板函数/类? - How do I use trigonometric functions for template functions/classes? C++ 中的多态性:我是否必须给孩子 class 功能与父母相同的 arguments - 如何重载 - Polymorphism in C++: Do I have to give child class functions the same arguments as the parents - how to overload 是否可以编写c ++模板/宏来检查两个函数是否具有相同的签名 - Is it possible to write c++ template/macros to check whether two functions have the same signatures 为什么这两个代码片段具有相同的效果? - Why do these two code snippets have the same effect?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM