C++ 在类设计的外部命名空间中查找重载运算符
如何让名称空间中的包装类知道在外部/全局名称空间中,它包装的对象可能存在重载运算符? 注意:我听说过ADL或Koenig查找,但我遇到了一个真正的问题 真正的设计问题 我想设计一个只有标题的库。假设我将所有内容都放在命名空间C++ 在类设计的外部命名空间中查找重载运算符,c++,C++,如何让名称空间中的包装类知道在外部/全局名称空间中,它包装的对象可能存在重载运算符? 注意:我听说过ADL或Koenig查找,但我遇到了一个真正的问题 真正的设计问题 我想设计一个只有标题的库。假设我将所有内容都放在命名空间my中。与此问题相关的部分可以简化为类似于模板包装的item // my.hpp #include <iostream> namespace my { template<typename T> struct item {
my
中。与此问题相关的部分可以简化为类似于模板包装的item
// my.hpp
#include <iostream>
namespace my
{
template<typename T>
struct item
{
T thing;
item(T t) : thing(t) {}
};
template<typename T>
std::ostream & operator<<(std::ostream & os, const item<T> & it)
{
os << it.thing;
return os;
}
}
及
在user.cpp
开始时,一切都会很好,g++user.cpp
将按预期编译
但是,如果用户更改了订单并将
#include "my.hpp"
#include "user.hpp"
编译器将生成一个错误,说明
my.hpp: In function 'std::ostream& my::operator<<(std::ostream&, const my::item<T>&)':
my.hpp:15:23: error: '::operator<<' has not been declared
在阅读了一篇关于meta的文章,并根据评论中的建议,我在我自己的问题中移动了一些“更新”,并将它们作为自我回答正式发布。我这样做是希望这将有助于将来遇到同样问题的人。谢谢大家!
正如@xskxzr在评论中正确指出的,用户代码中存在一些不好的地方。具体来说,
声明其参数均为std
实体的函数/操作是不好的,因为您无法将此类声明添加到std中以利用ADL
在这种情况下,问题在于用户,而不是设计者
现在,如果用户进行了更改
// user.hpp
#include <iostream>
#include <vector>
// CHANGE: (privately) inherit from std::vector<double>, rather than overload directly
struct DoubleVector : private std::vector<double>
{
using std::vector<double>::vector;
friend
std::ostream & operator<<(std::ostream &, const DoubleVector &);
};
std::ostream & operator<<(std::ostream &, const DoubleVector &);
//user.hpp
#包括
#包括
//CHANGE:(私下)从std::vector继承,而不是直接重载
struct DoubleVector:private std::vector
{
使用std::vector::vector;
朋友
std::ostream&operator此示例的可能副本表明,声明参数均为std实体的函数/操作是不好的,因为您无法将此类声明添加到std中以利用ADL。在我看来,避免此类函数/操作是用户的责任。但是,他可以声明新的Vector
类(可以继承std::vector
)并在vector
@xskxzr上声明操作。谢谢!经过再三考虑,我完全明白了。你需要填写答案。@darune谢谢。就这么做了。
#include "my.hpp"
#include "user.hpp"
my.hpp: In function 'std::ostream& my::operator<<(std::ostream&, const my::item<T>&)':
my.hpp:15:23: error: '::operator<<' has not been declared
g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0
// user.hpp
#include <iostream>
#include <vector>
// CHANGE: (privately) inherit from std::vector<double>, rather than overload directly
struct DoubleVector : private std::vector<double>
{
using std::vector<double>::vector;
friend
std::ostream & operator<<(std::ostream &, const DoubleVector &);
};
std::ostream & operator<<(std::ostream &, const DoubleVector &);
// user.cpp
#include "my.hpp"
#include "user.hpp"
#include <iostream>
#include <vector>
// CHANGE: use a user-defined DoubleVector class
std::ostream & operator<<(std::ostream & os, const DoubleVector & c)
{
for (const auto & e : c)
os << e << " | ";
return os;
}
int main()
{
DoubleVector vec = {3.14, 2.83};
std::cout << my::item<DoubleVector>(vec);
}