我为operator<<
实例定义了一个std::pair
输出函数,供一些想要在不注意预期的情况下打印值的单元测试使用。我的测试代码还具有成对的对,这些对作为具有自己的operator<<
的另一个类(特别是boost::optional
)的成员而保留,但是为了举例说明,我在这里定义了一个简单的Container
类代替。问题是operator<<
的{{1}}值似乎在容器类的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;
}
。这是来自GCC的消息:
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和Apple的Clang 1000.11中,我得到了相同的错误,但措辞却不同。 45.5(Apple LLVM 10.0.0,带有-std=c++14
。)
如果我删除-std=c++17
模板及其Container
周围的匿名名称空间,该错误就会消失。但这并不是真正的解决方案,因为实际上容器是operator<<
,它当然在命名空间boost::optional
中,而我不能更改它。
我不清楚为什么我的全局boost
在名称空间中不可见,因为全局范围应该是不合格查找的搜索路径的一部分。我最好的猜测是,这是因为我的operator<<
是一个模板,并且模板似乎不属于初始不合格查找的一部分,因此ADL会启动并找到在其中定义的其他一些operator<<
函数operator<<
并作为std::
中的成员,因此查找在此处停止。候选函数列表(在编译器的错误消息中)似乎与该解释一致。但是尚不清楚当容器不在命名空间中时为什么起作用。
有没有一种方法可以在不修改std::ostream
类的情况下完成这项工作?
(作为背景:我正在使用Boost.Test库,并编写类似Container
的行,其中BOOST_TEST(some_func() == boost::make_optional(std::make_pair('a', 1)))
做一些宏/模板魔术来提取表达式的两侧并输出其值如果它们不匹配,则需要定义一个值BOOST_TEST
。Boost为operator<<
提供了一个值,而我为其中的optional
写了一个值,但是调用从前者到后者就是问题所在。)
答案 0 :(得分:7)
不合格的查询一次上升一个级别,一旦找到内容就停止。它会在匿名名称空间(您正在从中调用的名称空间)中找到一个operator<<
,并在那里停止死亡。
请考虑将pair
或pair
本身的元素包装到您自己的命名空间中的包装器中。然后,您可以定义一个operator<<
以执行您想要的任何事情,并由ADL对其进行提取。
答案 1 :(得分:2)
是否可以在不修改Container类的情况下完成这项工作?
是的。您必须将operator<<
放在名称空间中。
DEMO在这里。
搜索运算符<<
仅在定义于Related Post中的命名空间container.value
中发生。