2011-09-16 50 views
6

我试图做这种方式:如何重载operator <<用于C++中的数组?

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

但可以T表示数组?为数组过载<<运算符是否正确?


编辑:

根据Kerrek SB的建议,这里是我的<<实现:

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; 
} 

是我实现吗?我收到了编译错误。

回答

7

你可以这样做:

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

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

如果可能,可能最好使它内联,因为每个N都会导致单独实例化。 (该pretty printer有这样的一个例子。)

你会发现,虽然,毯子模板带来了模棱两可的,因为os << "Hello"现在有两个可能的过载:模板匹配const char (&)[6],和(非模板)过载衰减到指针const 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_fundamental<T>替换is_same<T, char>以获得更多检查(但用户仍然不能将其用于标准库类型的数组)。

+0

谢谢,不过我还是要说不明白为什么它会导致每个N单独实例化,如果没有实现内联? – Alcott

+0

嗯,它是一个模板,所以每个模板实例最终都可以作为二进制文件中的一个独立函数。如果你内联,你可以完全避免函数调用,尽管这最终取决于编译器。 –

+0

明白了。用这个运算符<<有2个模板参数,我怎样才能指定第二个参数N?显然,我不能仅仅使用“cout << ar;”,我可以吗? – Alcott

3

另一种方法可以做到这一点会是像下面这样:

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); 

一加是它也将动态数组工作(即阵列您在堆上分配等)

+0

我会试试看。谢谢 – Alcott

+0

我有一种很微弱的感觉,如果你的'T'不是用户定义的类型,那么你可能在ADL遇到麻烦,尽管我不能确定。 –

+0

我用'int'等内建类型测试过它......似乎工作得很好......我想不出为什么这会与ADL规则相冲突。如果你有一个'std :: pair '对象,模板应该能够推导出类型'T',并且拒绝使用'std :: pair '的任何实例,其中'U'不是'int'类型的' 。 – Jason