【发布时间】:2016-08-01 14:04:52
【问题描述】:
我在使用标准指定的两阶段查找时遇到问题,并且(正确地)由 clang 实现,与 std::ostream 和 std::vector 的 operator<< 过载有关。
考虑一个非常通用的模板函数,它将其参数转换为流(仅在递归时才真正有用,但简单的示例足以引发问题):
// 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) 接受,但 clang 抱怨 call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup。
令人讨厌的是,clang 是正确的,我想在我的代码中解决这个问题。据我所知,有三个选项:
将
operator<<的定义移到shift()之前。这样做的缺点是,当包含一些(可能是其他)间接包含generic.h和vector.h的文件时,还必须注意正确排序。使用自定义命名空间,将
std所需的所有内容导入该命名空间,并在该命名空间内的新命名空间类上定义运算符,以便 ADL 可以找到它。在
std命名空间中定义operator<<。我认为这是未定义的行为。
我错过了任何选择吗?一般而言,为std-only 类的函数定义重载的最佳方法是什么(如果我想转移NS::MyClass,则问题不存在,因为那时我可以在NS 中定义运算符)。
【问题讨论】:
标签: c++ templates c++11 language-lawyer