gpt4 book ai didi

c++ - 从 std::ostream_iterator 调用时未找到运算符 << 的重载?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:10:46 25 4
gpt4 key购买 nike

这个程序

// 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<<namespace 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 << " >";
}
}

注意:您只能在 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. 在不了解参数相关查找的情况下,编译器能够找到使 (1) 工作所需的合适重载可能会让您感到惊讶。

    ADL 声明在函数调用中使用非限定名称 时,不仅会搜索当前命名空间以寻找合适的重载,还会搜索参数的命名空间;这就是编译器找到 N::func 的方式,即使我们没有写得那么明确。

  2. 我们在当前命名空间中有一个合适的重载;一切都很好。

  3. ...

    为什么 (3a) 编译,而 (3b) 会导致讨厌的诊断?

    当我们实例化模板时N::call_func<T>它将尝试传递 T 类型的参数到名为 funcunqualified 函数.

    因为 name-lookup 的规则说当前命名空间,涉及的参数的命名空间,在我们调用函数的情况下搜索合适的匹配项从一个不合格的名称,如果T,它将搜索 namespace N是在命名空间 N 中声明的类型。

    两者都是 N::AN::B命名空间 N 中声明,因此编译器不会搜索任何其他范围以找到合适的重载;这就是查找失败的原因。

关于c++ - 从 std::ostream_iterator 调用时未找到运算符 << 的重载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24110928/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com