繁体   English   中英

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

[英]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::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;
}

在 C++20 之前,你可以用 trait 和std::enable_if做类似的事情

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM