代码之家  ›  专栏  ›  技术社区  ›  YotKay

模板模板参数-这种情况下为什么需要这些参数?

c++
  •  -1
  • YotKay  · 技术社区  · 6 年前

    我试图弄明白为什么下面的代码(其中编写了流输出操作符函数的模板)需要使用模板模板参数:

    https://wandbox.org/permlink/W85pV5GhVzI95b3e

    #include <iostream>
    #include <vector>
    #include <deque>
    #include <list>
    
    template<template <class> class C, class T>
    std::ostream& operator <<(std::ostream& os, const C<T>& objs)
    {
        for (auto const& obj : objs)
            os << obj << ' ';
        return os;
    }
    
    int main()
    {
        std::vector<float> vf { 1.1, 2.2, 3.3, 4.4 };
        std::cout << vf << '\n';
    
        std::list<char> lc { 'a', 'b', 'c', 'd' };
        std::cout << lc << '\n';
    
        std::deque<int> di { 1, 2, 3, 4 };
        std::cout << di << '\n';
    
        return 0;
    }
    

    为什么我不能这样编写运算符函数的模板:

    template <class T>
    std::ostream& operator <<(std::ostream& os, T& objs) {...}
    

    在这种情况下,我会遇到很多错误,比如: 错误:“operator”的重载不明确(<<'(操作数类型为“std::ostream”{aka“std::basic\u ostream”}和“const char”) 操作系统(<)<目标(&L)<'';

    有人能帮我理解这一点吗?

    3 回复  |  直到 6 年前
        1
  •  3
  •   StoryTeller - Unslander Monica    6 年前

    虽然我同意 Jarod42 您不需要template-template参数,请允许我为您的具体案例演示一个更简单的解决方案:

    template<class T>
    auto operator <<(std::ostream& os, T const& objs)
      -> decltype(std::begin(objs), std::end(objs), (os))
    {
        for (auto const& obj : objs)
            os << obj << ' ';
        return os;
    }
    

    某个表达式SFINAE的尾部返回类型,所有内容都按您的要求工作。SFINAE部分发生在 decltype() 返回类型。逗号运算符使其成为 std::begin(objs) ,则, std::end(objs) 然后 (os) 检查是否结构良好。如果其中任何一个格式不正确,则不考虑使用该函数来解决重载问题。但由于逗号运算符的类型与其最后一个操作数的类型相同,我们得到 std::ostream& 从…里面 (操作系统) 由于 decltype 扣除规则。

    为什么? std::begin std::end ?碰巧它们对于几乎所有类型都是格式良好的,您可以将它们馈送到基于范围的for循环。因此,检查将覆盖任何遵守基于范围的for循环的迭代协议的类型。

    Here it is, live

        2
  •  2
  •   Jarod42    6 年前

    模板模板参数不是必需的。

    代码的作者假设iterable对象将是这种形式 C<T> ,这是错误的:

    • 存在 <T> 这是不可接受的,因为 std::unique_ptr<T> 。。。
    • std::vector 之前有更多参数(默认)等 C++2a ,它不会匹配 <T>

    使用特征(如 that question )最好是:

    template<class T, std::enable_if_t<is_iterable<T>::value>* = nullptr>
    std::ostream& operator <<(std::ostream& os, const T& objs)
    {
        for (auto const& obj : objs)
            os << obj << ' ';
        return os;
    }
    
        3
  •  0
  •   informant09    6 年前

    您不能这样编写模板:

    template <class T>
    std::ostream& operator <<(std::ostream& os, T& objs) {...}
    

    因为这会使ostream的每(!)个对象 T可以是任何东西,而不仅仅是列表。

    我认为最好的解决方法是为您想要的每种类型的列表指定重载。 E、 g:

    template <class T>
    std::ostream& operator <<(std::ostream& os, std::vector<T>& objs) {...}
    
    template <class T>
    std::ostream& operator <<(std::ostream& os, std::list<T>& objs) {...}
    

    等等