// main.cpp
#include <iostream>
#include <utility>
#include <algorithm>
#include <iterator>
#include <map>
template<typename t1, typename t2>
std::ostream& operator<<(std::ostream& os, const std::pair<t1, t2>& pair)
{
return os << "< " << pair.first << " , " << pair.second << " >";
}
int main()
{
std::map<int, int> map = { { 1, 2 }, { 2, 3 } };
std::cout << *map.begin() << std::endl;//This works
std::copy(
map.begin(),
map.end(),
std::ostream_iterator<std::pair<int,int> >(std::cout, " ")
); //this doesn't work
}
no match for ‘operator<<’ (operand types are ‘std::ostream_iterator<std::pair<int, int> >::ostream_type {aka std::basic_ostream<char>}’ and ‘const std::pair<int, int>’)
std::copy
内部的重载不可用,但为什么会这样?答案 0 :(得分:7)
由于未命名的方式从命名空间std 内部调用operator<<
(更具体地说,在 std :: ostream_iterator 内部) ,并且所涉及的所有参数也在同一名称空间中声明,仅名称空间std
将搜索潜在的匹配。
namespace std {
template<typename t1, typename t2>
std::ostream& operator<<(std::ostream& os, const std::pair<t1, t2>& pair)
{
return os << "< " << pair.first << " , " << pair.second << " >";
}
}
注意:您只能在namespace std
内专门化包含用户定义类型的模板,因此上述代码段可能会格式不正确标准(如果std::pair<T1,T2>
不是用户声明的类型,请参阅this discussion)。
下面我们有 namespace N ,它将帮助我们尝试模拟你对 namespace std 的使用,以及当编译器试图找到合适的重载时发生了什么对于给定的类型。
名称空间N
namespace N {
struct A { };
struct B { };
void func (A value) { std::cout << "A"; }
template<class T>
void call_func (T value) { func (value); }
}
<强>的main.cpp 强>
void func (N::B value) {
std::cout << "B";
}
int main() {
N::A a;
N::B b;
func (a); // (1)
func (b); // (2)
N::call_func (a); // (3a)
N::call_func (b); // (3b)
}
备注强>:
如果不了解依赖于参数的查找,可能会惊讶于编译器能够找到使( 1 )工作所需的合适重载。
ADL声明,在函数调用中使用 unqualified-name 时,不仅会搜索当前命名空间的合适重载,还会搜索参数的命名空间;这就是编译器找到N::func
的方式,即使我们没有明确写出来。
我们在当前命名空间中有一个合适的重载;它在引擎盖上都很好。
...
为什么(3a)会编译,而(3b)会导致讨厌的诊断?
当我们实例化模板N::call_func<T>
时,它会尝试将T
类型的参数传递给名为func
的非限定函数。
由于 name-lookup 的规则表示当前命名空间和所涉及参数的命名空间,因此我们在调用函数时会搜索合适的匹配项如果T
是名称空间N中声明的类型,则非限定名称将仅搜索名称空间N EM>
命名空间N 中都声明了N::A
和N::B
,因此编译器将不搜索任何其他范围以查找合适的重载;这就是查找失败的原因。
答案 1 :(得分:1)
虽然这个问题已经得到解答,但我只是想补充说,有一种更好的方法来打印地图而不会滥用复制功能。 还有一个转换函数,更适合做这样的事情。 我重写了你的例子,给你一个提示,你可以使用transform函数将map转换成字符串并将它们打印到std :: cout:
#include<iostream>
#include<map>
#include<algorithm>
#include<sstream>
template<typename t1, typename t2>
std::ostream& operator<<(std::ostream& os, const std::pair<t1, t2>& pair)
{
return os << "< " << pair.first << " , " << pair.second << " >";
}
std::string toString(const std::pair<int, int>& pair) {
std::ostringstream str;
str << "<" << pair.first << ", " << pair.second << ">";
return str.str();
}
int main()
{
std::map<int, int> map = { std::make_pair(1, 2), std::make_pair(2, 3)};
std::cout << *map.begin() << std::endl;//This works
std::transform(map.begin(), map.end(),
std::ostream_iterator<std::string>(std::cout, "\n"), toString);
}