ostream_iterator 对于矢量<int> 不编译。为什么?
ostream_iterator for a vector<int> does not compile. Why?
请参阅以下最小可重现示例:
#include <iostream>
#include <vector>
#include <algorithm>
// Define inserter operator for std::vector<int>
std::ostream& operator << (std::ostream& os, const std::vector<int>& v) {
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(os, " "));
return os;
}
// Define inserter operator for std::vector<std::vector<int>>
std::ostream& operator << (std::ostream& os, const std::vector<std::vector<int>>& vv) {
// ******* Error in this line *****
std::copy(vv.begin(), vv.end(), std::ostream_iterator<std::vector<int>>(os,"\n"));
// OK. The following works and will call the operator above
for (const std::vector<int>& v : vv) os << v << '\n';
return os;
}
int main() {
std::vector<std::vector<int>> vvi{ {1,2}, {3,4,5}, {6,7,8,9 } };
std::cout << vvi;
return 0;
}
std::ostream_iterator<std::vector<int>>
不会编译,编译器说:
binary '<<': no operator found which takes a right-hand operand of type 'const _Ty' (or there is no acceptable conversion)
尽管 std::vector<int>
的插入操作员可用。
如果我改为使用:
for (const std::vector<int>& v : vv) os << v << '\n';
将调用 std::vector<int>
的插入运算符。但在 std::ostream_iterator
.
的情况下不是
CppReference 对我没有帮助。
为什么不能编译?
第一个问题是你缺少一个
#include <iterator>
您表示您已经熟悉 cppreference.com,因此您应该注意 std::ostream_iterator
被注明需要此头文件。
但编译失败的真正原因是重载运算符被std::copy
调用,自然是在std
命名空间中。由于调用 <<
运算符的代码位于 std
命名空间中,因此重载解析会在 std
命名空间中搜索 <<
的已定义重载,并找到一大堆重载, 对于各种本地类型。所有这些重载决议都失败了。 None 其中 std::vector<int>
。搜索全局命名空间 not 以查找您的自定义 <<
重载,因为至少找到一个 <<
重载在 std
命名空间中。游戏结束。
如果 std
命名空间中没有定义的 <<
重载,那么重载解析最终会找到您的自定义重载。唉,事实并非如此。
消除编译错误的一种方法是将重载放入 std
命名空间:
namespace std {
// Define inserter operator for std::vector<int>
std::ostream& operator << (std::ostream& os, const std::vector<int>& v) {
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(os, " "));
return os;
}
}
然而,this is pedantic undefined behavior。无论如何,这就是编译错误的原因:首先在 std
命名空间中搜索 <<
的现有重载,因为它们是从 std::copy
中调用的,并且现有的重载解决方案首先找到,因此不考虑其他名称空间中的其他潜在重载。
请参阅以下最小可重现示例:
#include <iostream>
#include <vector>
#include <algorithm>
// Define inserter operator for std::vector<int>
std::ostream& operator << (std::ostream& os, const std::vector<int>& v) {
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(os, " "));
return os;
}
// Define inserter operator for std::vector<std::vector<int>>
std::ostream& operator << (std::ostream& os, const std::vector<std::vector<int>>& vv) {
// ******* Error in this line *****
std::copy(vv.begin(), vv.end(), std::ostream_iterator<std::vector<int>>(os,"\n"));
// OK. The following works and will call the operator above
for (const std::vector<int>& v : vv) os << v << '\n';
return os;
}
int main() {
std::vector<std::vector<int>> vvi{ {1,2}, {3,4,5}, {6,7,8,9 } };
std::cout << vvi;
return 0;
}
std::ostream_iterator<std::vector<int>>
不会编译,编译器说:
binary '<<': no operator found which takes a right-hand operand of type 'const _Ty' (or there is no acceptable conversion)
尽管 std::vector<int>
的插入操作员可用。
如果我改为使用:
for (const std::vector<int>& v : vv) os << v << '\n';
将调用 std::vector<int>
的插入运算符。但在 std::ostream_iterator
.
CppReference 对我没有帮助。
为什么不能编译?
第一个问题是你缺少一个
#include <iterator>
您表示您已经熟悉 cppreference.com,因此您应该注意 std::ostream_iterator
被注明需要此头文件。
但编译失败的真正原因是重载运算符被std::copy
调用,自然是在std
命名空间中。由于调用 <<
运算符的代码位于 std
命名空间中,因此重载解析会在 std
命名空间中搜索 <<
的已定义重载,并找到一大堆重载, 对于各种本地类型。所有这些重载决议都失败了。 None 其中 std::vector<int>
。搜索全局命名空间 not 以查找您的自定义 <<
重载,因为至少找到一个 <<
重载在 std
命名空间中。游戏结束。
如果 std
命名空间中没有定义的 <<
重载,那么重载解析最终会找到您的自定义重载。唉,事实并非如此。
消除编译错误的一种方法是将重载放入 std
命名空间:
namespace std {
// Define inserter operator for std::vector<int>
std::ostream& operator << (std::ostream& os, const std::vector<int>& v) {
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(os, " "));
return os;
}
}
然而,this is pedantic undefined behavior。无论如何,这就是编译错误的原因:首先在 std
命名空间中搜索 <<
的现有重载,因为它们是从 std::copy
中调用的,并且现有的重载解决方案首先找到,因此不考虑其他名称空间中的其他潜在重载。