我可以将内置数组传递给 std::ostream_iterator 而无需数组到指针衰减吗?

Can I pass a built-in array to std::ostream_iterator without an array-to-pointer decay?

我重载了 operator<< 以打印内置数组 const int (&arr)[N]:

template <size_t N>
std::ostream& operator<<(std::ostream& os, const int (&arr)[N])
{
    os << "{ ";
    bool first{true};
    for (int i : arr)
    {
        os << (first ? "" : ", ") << i;
        first = false;
    }
    return os << " }";
}

我可以用它打印一个 const int (&)[5] 数组到 std::cout:

    int arr[3][5] = {{3, 4, 6, 1, 1}, {6, 3, 4, 5, 1}, {6, 1, 2, 3, 3}};

    for (const auto& subarr : arr) { std::cout << subarr << "\n"; }

// Outputs:
//
//   { 3, 4, 6, 1, 1 }
//   { 6, 3, 4, 5, 1 }
//   { 6, 1, 2, 3, 3 }

但是,当我尝试通过 std::copystd::ostream_iterator<const int (&)[5]> 打印相同的数组时,我只打印出数组地址:

std::copy(std::cbegin(arr), std::cend(arr),
        std::ostream_iterator<const int (&)[5]>{std::cout, "\n"});

// Outputs:
//
//   0x7ffec4f84db0
//   0x7ffec4f84dc4
//   0x7ffec4f84dd8

我想数组正在衰减到 ostream_iterator 末端的指针。如果是这样,有没有办法避免这种情况?

[Demo] 工作版本。


此站点中有很多关于数组到指针衰减的问题,但我还没有看到对这种情况有帮助的问题。

实际上,this answer 说:

[...] you can also prevent decay in your original version of f if you explicitly specify the template agument T as a reference-to-array type

f<int (&)[27]>(array);

但是在构造 ostream_iterator 时似乎并没有发生这种情况。

这与 array-to-pointer 衰减无关,而与名称查找的工作方式有关。

在这个版本中:

for (const auto& subarr : arr) { std::cout << subarr << "\n"; }

您的 operator<< 是一个候选者,因为常规的不合格查找会找到它。

但这不是 ostream_iterator 所做的,它的内部实现将做这样的事情:

template <typename T>
void whatever(std::ostream& os, T const& arg) {
    os << arg;
}

并且 os << arg 调用不会通过不合格的查找找到您的 operator<< 候选人(它不会在 header 的定义点声明)和它不会通过 argument-dependent 查找找到您的 operator<< (因为它不在任一参数的关联名称空间中)。由于您的函数不是候选函数,而是选择的函数是指针函数 - 这就是为什么它按照它的方式格式化的原因。

一个(不好的,不要这样做)解决方案是将 operator<< 重载放在 namespace std 内,这将导致 argument-dependent 查找能够实际找到它。但是不要这样做,因为不允许您将东西添加到 namespace std(并且,一般来说,不应该将您的东西添加到其他人的名称空间)。

因此,更好的解决方案是创建您自己的类型,按照您希望的方式进行格式化,从那时起,您只需添加一个 operator<< 即可正确关联 - 以一种不不涉及搞乱 std.