运算符重载<<从 std::ostream_iterator 调用时未找到?
Overload of operator<< not found when called from std::ostream_iterator?
程序
// 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
,但为什么呢?
说明
由于operator<<
在命名空间std内部以不限定的方式调用(更具体地说在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 << " >";
}
}
注意:您只能专门化包含用户定义类型的模板在 下面我们有命名空间N,这将帮助我们模拟你对命名空间std的使用,以及当编译器试图为给定类型找到合适的重载时会发生什么。 名称空间N main.cpp <一口>一口> : 在不知道参数相关查找的情况下,人们可能会对编译器能够找到使(1)工作所需的合适的重载感到惊讶。 ADL规定,在函数调用中使用非限定名称时,不仅要搜索当前名称空间以查找合适的重载,还要搜索参数的名称空间;这就是编译器找到 我们在当前命名空间中有一个合适的重载;namespace std
中,因此根据标准,上面的代码片段可能是病态的(如果std::pair<T1,T2>
不是用户声明的类型,请参阅本讨论)。
详细说明namespace N {
struct A { };
struct B { };
void func (A value) { std::cout << "A"; }
template<class T>
void call_func (T value) { func (value); }
}
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)
}
N::func
的方式,尽管我们没有明确地写。
……
为什么(3a)可以编译,而(3b)会导致一个讨厌的诊断?
当我们实例化模板N::call_func<T>
时,它将尝试将T
类型的参数传递给名为func
的非限定函数。
由于name-lookup规则规定,如果从不合格的名称调用函数,将搜索当前命名空间和所涉及的参数的命名空间以寻找合适的匹配,因此,如果T
是在命名空间N中声明的类型,则将仅搜索命名空间N。
N::A
和N::B
都是在命名空间N中声明的,因此编译器将不会在中搜索任何其他作用域来找到合适的重载;
虽然这个问题已经得到了回答,但我只想补充一下,有一种更好的方法可以在不滥用复制功能的情况下打印地图。还有一个变换函数更适合做这样的事情。我重写了您的示例,以给您提示如何使用transform函数将映射转换为字符串并将它们打印到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);
}
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 函数调用中参数的顺序重要吗
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在c++类上调用void函数
- 为什么 std::unique 不调用 std::sort?
- 调用专用模板时出错"no matching function for call to [...]"
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 选择要调用的构造函数
- C++为什么尽管我调用了void函数,它却不起作用
- 构造函数正在调用一个使用当前类类型的函数
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 错误:调用"std::vector<:vector<int>>::p ush_back(std::vector<std::__cxx11::basic_string<
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- C++运算符<<调用::ostream而不是std::osttream
- C++是否可以将fstream对象设置为在每次调用<<
- 我可以使用define调用运算符<<