我能够定义和使用:
std::ostream& operator<<(std::ostream& os, std::vector<int> const& container)
{
for (auto const& n : container)
os << n << ", ";
return os;
}
int main()
{
std::vector<int> data{0,1,2};
std::cout << data << '\n';
}
( demo )
但该运算符的定义并不取决于我使用的容器类型。从那里,我想定义一个模板化版本:
template<class Iterable>
std::ostream& operator<<(std::ostream& os, Iterable const& iterable)
{
for (auto const& n : iterable)
os << n << ", ";
return os;
}
int main()
{
std::vector<int> data{0,1,2};
std::cout << data << '\n';
}
( demo )
这是我的编译器生气并冗长地拒绝它的地方:
error: ambiguous overload for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'char')
...有很多可能的候选人。
为什么它不合法,我该如何定义这样的运算符?
最佳答案
如其他 StackOverflow 问题所述,How do I fix “ambiguous overload” error when overloading operator<< (templated)?
, 在定义 operator<<(std::ostream&, T)
时对于所有 T
,您为现有 operator<<
的类型重载它存在。因此模棱两可的电话:
os << n << ", ";
^-- recursively calls itself? or calls the overload provided by the Standard Library?
解决方案是使用SFINAE确保只为可迭代类型定义重载。自range-based for loop的定义基于begin
和 end
, 我们可以用它来区分什么是 Iterable
:
template<class Iterable, class = std::void_t<decltype(begin(std::declval<Iterable>()))>>
std::ostream& operator<<(std::ostream& os, Iterable const& iterable)
{
for (auto const& n : iterable)
os << n << ", ";
return os;
}
( demo )
现在,std::cout << data
调用你的版本和std::cout << '\n'
调用内置重载,因为 Iterable = char
的替换失败: begin(char)
未定义。
关于c++ - 为可迭代对象定义模板运算符<<,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53267436/