【问题标题】:how overload operator<< for an array in C++?如何在 C++ 中为数组重载 operator<<?
【发布时间】:2011-09-16 01:14:56
【问题描述】:

我正在尝试这样做:

template <typename T>
ostream &operator<<(ostream &os, T &arr)
{ /*...*/ }

但是T 可以代表一个数组吗?为数组重载&lt;&lt; 运算符是否正确?


编辑:

根据 Kerrek SB 的建议,这是我对 &lt;&lt; 的实现:

template <typename T, unsigned int N>
ostream &operator<<(ostream &os, const T (&arr)[N])
{
    int i;
    for(i = 0; i < N; i++)
        os << arr[i] << " ";
    os << endl;
    return os;
}

我的实现正确吗?我遇到了编译错误。

【问题讨论】:

    标签: c++ operator-overloading


    【解决方案1】:

    你可以这样做:

    template <typename T, unsigned int N>
    std::ostream & operator<<(std::ostream & os, const T (&arr)[N])
    {
      // ..
      return os;
    }
    

    当然,这只适用于编译时数组。请注意,当T 是内置类型或std 命名空间中的类型时,不允许实例化此模板!

    如果可能,最好将其设为内联,因为您将为每个 N 单独实例化。 (pretty printer 有一个例子。)

    不过,您会注意到,总括模板引入了歧义,因为 os &lt;&lt; "Hello" 现在有两个可能的重载:匹配 const char (&amp;)[6] 的模板,以及衰减指针 @ 的(非模板)重载987654328@,两者具有相同的转换序列。我们可以通过禁用 char 数组的重载来解决这个问题:

    #include <ostream>
    #include <type_traits>
    
    template <typename T, unsigned int N>
    typename std::enable_if<!std::is_same<T, char>::value, std::ostream &>::type
    operator<<(std::ostream & os, const T (&arr)[N])
    {
      // ..
      return os;
    }
    

    其实更通用的你也可以将basic_ostream参数模板参数化:

    template <typename T, unsigned int N, typename CTy, typename CTr>
    typename std::enable_if<!std::is_same<T, char>::value,
                            std::basic_ostream<CTy, CTr> &>::type
    operator<<(std::basic_ostream<CTy, CTr> & os, const T (&arr)[N])
    {
      // ..
      return os;
    }
    

    鉴于T 必须是用户定义的类型,您甚至可以将is_same&lt;T, char&gt; 替换为is_fundamental&lt;T&gt; 以进行更多检查(但用户仍然不能将其用于标准库的数组类型)。

    【讨论】:

    • 谢谢,但我不明白为什么如果没有内联实现它会导致每个 N 单独实例化?
    • 嗯,它是一个模板,所以每个模板实例最终都可能在你的二进制文件中成为一个单独的函数。如果你内联,你可以完全避免函数调用,尽管这最终取决于编译器。
    • 知道了。有了这个 operator
    • 试试看 :-) 这是一个模板函数,所以模板参数扣除适用,你不必指定任何东西:int a[10]; std::cout &lt;&lt; a;.
    • 好吧,我得到了编译错误,我将编辑我的帖子以添加我的实现
    【解决方案2】:

    您可以这样做的另一种方法如下:

    template<typename T>
    ostream& operator<<(ostream &out, const std::pair<T, int>& array)
    {
        //...code
        return out;
    }
    

    其中T 将采用指向数组的指针(即,它将是数组将衰减到的指针类型),并且该对的int 部分将是数组的大小。然后你可以像下面这样使用它:

    int array[10];
    //...some code that initializes array, etc.
    
    cout << make_pair(array, 10);
    

    此方法的一个优点是它也适用于动态数组(即,您在堆上分配的数组等)

    【讨论】:

    • 我有一种非常微弱的感觉,如果您的 T 不是用户定义的类型,您可能会在这里遇到 ADL 问题,尽管我不能确定。
    • 我使用像int 这样的内置类型对其进行了测试......似乎工作得很好......我想不出为什么这会与ADL规则冲突。如果你有一个std::pair&lt;T, U&gt; 对象,模板应该能够推断出T 类型,并拒绝使用std::pair&lt;T, U&gt; 的任何实例化,其中U 不是int 类型。
    最近更新 更多