我可以将内置数组传递给 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::copy
到 std::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
.
我重载了 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::copy
到 std::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 agumentT
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
.