跳到主要内容

可以让输出流对象cout直接输出内置数组类型定义的变量吗?

·859 字·2 分钟

突发奇想

既然这个cout对象可以直接输出普通内置类型变量的值,还有自定义类类型也玩过;那么可以不可以使用cout直接输出内置数组的各个元素的值呢?比如像这样:

1
2
3
4
5
6
7
8
9
#include <iostream>

int main() {
    int arr[] = {1, 2, 343, 4, 56, 76,82};

    std::cout << arr << std::endl;

    return 0;
}

输出结果可以是:

1
[1,2,3,343,4,56,76,82]

普通方法

首先,内置数组的元素是可以变化的,那么为了适应不同的元素类型,需要一个函数模板,接收不同内置数组类型;其次就是数组元素必须已知,函数模板中需要一个固定参数保存数组元素大小的值。

  • 元素类型为T
  • 那么数组的类型就是T[N]
  • 加上引用和const就是const T(&arr)[N]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
template <typename T, size_t N>
std::ostream& operator<<(std::ostream& os, const T (&arr)[N]) {
    os << "[";

    for (int i = 0; i < N - 1; ++i) {
        os << arr[i] << ",";
    }

    os << arr[N - 1] << "]";

    return os;
}

既然要求是输出结果是[字符开头和]字符结尾,那么可以在模板函数内以字符串的形式输出,但是遇到了一个问题,看一下clangd的错误提示:

1
 Use of overloaded operator '<<' is ambiguous (with operand types 'std::ostream' (aka 'basic_ostream<char>') and 'const char[2]')

在提示中可以发现,在os « “[”; 这行代码中,在匹配"[“这个字符串类型的时候,匹配到了两个都符合的«运算符重载函数,此时,编译器会不知道选择哪一个,所以会产生二义性。二义性的原因就是右操作数匹配了多种类型。一个是编译器内置实现的basic_ostream,其实就是const char*,还有一个就是const char[2];第二个就是当前实现的«运算符重载函数,它也直接匹配到了,若没有编译器内置实现的函数的话,那么会一直递归调用当前实现的«运算符重载函数,有的话就产生二义性。那么该如何解决呢? 可以通过强制类型转换的方式去强制它匹配到一个«运算符重载函数,那么强转为const char[2]可以吗?绝对是不可以的,因为这会一直递归调用当前自定义实现的«运算符重载函数,那么只有将其转换为const char*了,修改以上的代码为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
template <typename T, size_t N>
std::ostream& operator<<(std::ostream& os, const T (&arr)[N]) {
    os << reinterpret_cast<const char*>("[");

    for (int i = 0; i < N - 1; ++i) {
        os << arr[i] << reinterpret_cast<const char*>(",");
    }

    os << arr[N - 1] << reinterpret_cast<const char*>("]");

    return os;
}

查看输出结果:

1
[1,2,343,4,56,76,82]