c++ - 为可迭代对象定义模板运算符<<

标签 c++ templates operator-overloading c++14

我能够定义和使用:

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的定义基于beginend , 我们可以用它来区分什么是 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/

相关文章:

c++ - 在不使用预编译头文件的 C++ 项目中编译 C 文件?

c++ - 如何打印此程序的终止?

C++简单数组元素比较

c++ - 数组下标的无效类型 `int[int]'

excel - 在 Excel VBA 中获取使用 "Save As"时使用的路径(从模板创建的文档!)

c++ - 将字符串重新定义为类

c++ - 无法为 GCC 128 位整数重载 std::abs()

c++ - 模板函数中的默认模板需要空角括号 <>

c++ - << 的运算符重载需要 const;产生头痛

ios - 重载单一平等在Swift中