c++ - 为什么命名空间中的函数看不到我的 operator<< 全局定义?
问题描述
我已经operator<<
为实例定义了一个输出函数std::pair
,供一些单元测试使用,如果他们没有看到预期的值,他们想要打印这些值。我的测试代码也有对,它们作为另一个类的成员持有operator<<
——特别是boost::optional
,但为了举例,我在Container
这里定义了一个简单的类。问题是operator<<
for值在容器类中std::pair
似乎不可见。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<<
for 对。这是来自 GCC 的消息:
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
,当然它在 namespaceboost
中,我无法改变它。
我不清楚为什么我的全局operator<<
在命名空间中不可见,因为全局范围应该是不合格查找的搜索路径的一部分。我最好的猜测是,这是因为 myoperator<<
是一个模板,并且模板似乎不是最初的非限定查找的一部分,所以 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
考虑将 of或pair
自身的元素包装到您自己的命名空间中的包装器中。然后你可以定义一个operator<<
做任何你想做的事情,并让 ADL 接受它。
推荐阅读
- symfony - Doctrine - 从没有根实体的多对多关系中检索集合
- unit-testing - IMapper 模拟返回 null
- java - 所有双向关系都可以是 LAZY 吗?
- javascript - 使用原始尺寸和流以锐利的方式裁剪图像
- c# - 如何实现保存或更新按钮。客户端
- cloudkit - 使用 CloudKit 访问 iCloud 便笺
- imgur - Imgur API 授权问题
- excel - 为什么我的 VBA 代码无法选择“下载”来下载此特定网站的 .xls 文件?
- python-2.7 - 相同的代码在命令行中工作,但不适用于其他人
- r - R cran 基于关键字的子集文本行