为什么命名空间中的函数看不到全局定义的运算符<<?
Why can't a function in a namespace see my operator<< defined globally?
我已经为std::pair
实例定义了一个operator<<
输出函数,供一些单元测试使用,这些单元测试希望在不监视预期内容时打印值。 我的测试代码也有对,这些对作为另一个类的成员持有,该类有自己的operator<<
- 特别是boost::optional
,但为了示例,我在这里定义了一个简单的Container
类。 问题是std::pair
值的operator<<
在容器类的operator<<
中似乎不可见。
#include <iostream>
#include <utility>
template <typename T1, typename T2>
std::ostream &operator<<(std::ostream &out, std::pair<T1, T2> const &pair) {
return out << "{ " << pair.first << ", " << pair.second << " }";
}
namespace {
template <typename T>
struct Container {
T value;
};
template <typename T>
std::ostream &operator<<(std::ostream &out, Container<T> const &container) {
return out << container.value; // Error!
}
}
int main() {
std::pair<char, int> pair { 'a', 1 };
Container<std::pair<char, int>> container { pair };
std::cout << pair << std::endl;
std::cout << container << std::endl;
}
输出普通对的末端附近的行工作正常。 但是,当尝试在容器中输出对时,编译器找不到对的operator<<
。 以下是来自海湾合作委员会的消息:
test.cc: In instantiation of ‘std::ostream& {anonymous}::operator<<(std::ostream&, const {anonymous}::Container<T>&) [with T = std::pair<char, int>; std::ostream = std::basic_ostream<char>]’:
test.cc:28:16: required from here
test.cc:18:16: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘const std::pair<char, int>’)
return out << container.value;
~~~~^~~~~~~~~~~~~~~~~~
。然后是一长串考虑的所有候选函数operator<<
,以及为什么每个函数都不适合(因为它们都适用于不同类型的值)。 我的std::pair
模板不在列表中。
(此消息来自 Debian 的 GCC 6.3.0-std=c++14
。 我从 Debian 的 Clang 3.8.1-24 和带有-std=c++14
的 Apple Clang 1000.11.45.5(Apple LLVM 10.0.0)和-std=c++17
中得到相同的错误,但措辞不同。
如果我删除Container
模板及其operator<<
周围的匿名命名空间,错误就会消失。 但这不是真正的解决方案,因为实际上容器是boost::optional
的,这当然是在命名空间boost
中,我无法更改它。
我不清楚为什么我的全局operator<<
在命名空间内不可见,因为全局范围应该是非限定查找的搜索路径的一部分。 我最好的猜测是,这是因为我的operator<<
是一个模板,而模板似乎不是初始非限定查找的一部分,因此 ADL 启动并找到一堆其他operator<<
函数在std::
中定义并作为std::ostream
中的成员,所以查找停止到此。 候选函数的列表(在编译器的错误消息中)似乎与该解释一致。 但是,目前还不清楚为什么当容器不在命名空间中时它确实有效。
有没有办法在不修改Container
类的情况下完成这项工作?
(作为背景:我正在使用 Boost.Test 库并编写像BOOST_TEST(some_func() == boost::make_optional(std::make_pair('a', 1)))
这样的行,其中BOOST_TEST
做一些宏/模板魔术来提取表达式的两侧,如果它们不匹配,则输出它们的值。 这要求值具有定义operator<<
。 Boost 为optional
提供了一个,我已经为其中的std::pair
写了一个,但从前者到后者的调用是问题所在。
非限定查找一次上升一个级别,一旦找到某些内容就会停止。它在匿名命名空间(您从中调用的命名空间)中找到一个operator<<
,并在那里停止。
请考虑将pair
元素或pair
本身包装到您自己的命名空间中的包装器中。然后,您可以定义一个operator<<
来执行任何您想要的操作,并让 ADL 选取它。
有没有办法在不修改容器类的情况下完成这项工作?
是的。您必须将operator<<
放在命名空间中。
在这里演示。
搜索运算符<<
仅在定义container.value
命名空间中进行。相关文章。
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 如何显式调用运算符<<
- 为什么COUT在朋友函数中不起作用,该功能超载了操作员&lt;&lt;这是一个iStream运算符
- C++运算符<<调用::ostream而不是std::osttream
- BOOST ::变体无法解决运算符&lt;&lt;对于STD :: Ostream
- 过载输出<<用于类的运算符,以打印其中的元组
- C++ostream:没有运算符匹配<<&应在'&'代币
- 重载运算符<<:此运算符函数的参数太多
- C++继承运算符<<
- 重载运算符<<用于模板类.即使使用好友关键字也无法获得私人会员
- 如何过载<<用于YAML::Emitter的运算符,以序列化包含另一个自定义类的向量的自定义类
- 为什么字符串流运算符<<擦除原始值
- 关于使用运算符<<为新手提供C++中的模板
- 我已经完成了<<运算符重载,但它'It’不起作用
- 重载运算符<<输出地址而不是数据成员
- 错误:没有匹配'运算符<<"在'std::cout
- 重载运算符<<用于ostream语法
- 当运算符<存在时,为什么要定义 LT?
- log4cxx访问异常,使用<<运算符和宏
- 重载<<运算符错误C2804:二进制'运算符<<'参数太多