问题描述
该程序
// 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
}
产生错误
我想这不起作用,因为我的重载在 std :: copy
中不可用,但是为什么呢?
I guess this isn't working because my overload isn't available inside std::copy
, but why is that?
推荐答案
说明
因为 operator<<
是从 namespace std 内部(更具体地说是在 std ::内部)以不合格的方式被调用的:ostream_iterator ),并且所有涉及的参数也都在同一名称空间中声明,仅 名称空间 std
会被搜索到.
Explanation
Since operator<<
is being called in an unqualified manner from inside namespace std (more specifically inside std::ostream_iterator), and all the arguments involved are also declared in the same namespace, only namespace std
will be searched for potential matches.
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 N ,这将帮助我们尝试模拟您对 namespace std 的用法,以及编译器尝试查找合适的重载时发生的情况给定类型.
Below we have namespace N which will aid us in trying to simulate your usage of namespace std, and what is going on when the compiler tries to find a suitable overload for a given type.
命名空间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 )工作所需的合适的重载,可能会让您感到惊讶.
Without knowing about Argument-dependent lookup, one might be surprised that the compiler is able to find the suitable overload required to make (1) work.
ADL指出,在函数调用中使用 unqualified-name 时,不仅会在当前名称空间中搜索适当的重载,还会搜索参数的名称空间.这就是编译器如何找到 N :: func
的方法,即使我们没有明确编写.
ADL states that upon using an unqualified-name in a function call, not only is the current namespace searched for suitable overloads, the namespace of the arguments are also searched; and this is how the compiler finds N::func
, even though we didn't write so explicitly.
我们在当前名称空间中有适当的重载;一切都很好.
We have a suitable overload in the current namespace; it's all good in the hood.
...
为什么(3a)会编译,而(3b)会导致讨厌的诊断?
当我们实例化模板 N :: call_func< T>
时,它将尝试将 T
类型的参数传递给 unqualified 名为 func
的函数.
When we instantiate the template N::call_func<T>
it will try to pass on the argument of type T
to the unqualified function named func
.
由于 name-lookup 的规则表明,在我们调用函数的情况下,会搜索当前名称空间和所涉及参数的名称空间以查找合适的匹配项如果 T
是在 namespace中声明的类型,则从不合格名称中,将仅搜索名称空间N .N .
Since the rules of name-lookup says that the current namespace, and the namespace of the arguments involved, are searched for suitable matches in case we are calling a function from a unqualified name, it will only search namespace N if T
is a type declared in namespace N.
N :: A
和 N :: B
都在 namespace N 中声明,因此编译器将不搜索其他范围以找到合适的重载;这就是查找失败的原因.
Both N::A
and N::B
are declared in namespace N, so the compiler will not search any other scope to find a suitable overload; which is why lookup fails.
这篇关于运算符的过载<<从std :: ostream_iterator调用时找不到?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!