对于和std::vector
的operator<<
过载,我无法使用标准中指定的(正确)clang实施的两相查找。使用通用模板函数专门化运算符<<用于std :: ostream和std :: vector的最佳方法?
考虑其转移参数转化为流一个非常通用的模板函数(实际上只用递归是有用的,但简单的例子就足以引发问题):
// generic.h
template<typename Stream, typename Arg>
void shift(Stream& s, Arg& arg) { s << arg; }
这generic.h可使用整个项目。然后,在一些其他文件中,我们要输出一个std::vector
,所以我们定义一个过载
// vector.h
#include <iostream>
#include <vector>
std::ostream& operator<<(std::ostream& s, std::vector<int> const& v) {
for(auto const& elem : v) { s << elem << ", "; }
return s;
}
和主文件中,我们首先(间接地)使用generic.h
,然后,由于一些其它包括,载体过载:
// main.cpp
#include "generic.h"
#include "vector.h"
int main() {
std::vector<int> v{1,2,3,4,5};
shift(std::cout, v);
}
此代码由GCC(5.4.0)和ICC(16.0)接受,但铛抱怨call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup
。
恼人的是,铿锵是对的,我想解决这个问题在我的代码。还有据我可以看到三个选项:
移动的
operator<<
定义shift()
之前。这具有的缺点是,当包括间接包括generic.h
和vector.h
的一些(可能是其他)文件时,还必须小心地对它们进行正确排序。使用自定义名称空间,将所需的所有内容从
std
导入该名称空间,并在名称空间内的新名称空间类上定义运算符,以便ADL可以找到它。在
std
命名空间中定义operator<<
。我认为这是未定义的行为。
我错过任何选项吗?一般来说,定义std
函数的重载最好的方法是什么 - 只有类(如果我想移动NS::MyClass
,则不存在问题,因为我可以在NS
中定义运算符)。
如果你要使用指针,你可能应该检查'nullptr'。否则,只需使用参考或可选类型 – KABoissonneault
是的。很显然,可以进行调整,具体取决于你想要如何使用它或者想要如何防守。引用的缺点是类型不可分配。如果这没关系,那么请使用参考。答案的要点是“使用适配器而不是为不属于你的类型重载操作符”,而不是“如何编写适合所有人的通用适配器”。 –
重新引用不可分配引用的缺点:使用如此轻量级的包装器,您可以随时重新创建一个,因此我同意@KABoissonneault使用引用而不是指针。 – TemplateRex