本文介绍了定义模板运算符<<对于可迭代的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以定义和使用:

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';
}

(演示)

但是该运算符的定义并不取决于我使用哪种容器.从那里,我想定义一个模板版本:

But the definition of that operator doesn't depend on what kind of container I use. From there, I'd like to define a templated version:

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';
}

(演示)

这是我的编译器生气并认真拒绝它的地方:

This is where my compiler gets angry and verbosily reject it:

error: ambiguous overload for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'char')

...有很多可能的候选人.

... with a lot of possible candidates.

为什么不合法,我该如何定义这样的运算符?

推荐答案

如另一个StackOverflow问题中所述,如何解决重载运算符时<歧义重载"错误. (有模板)?,当为所有T定义operator<<(std::ostream&, T)时,将其重载为现有operator<<存在的类型.因此,模棱两可的调用:

As stated in this other StackOverflow question, How do I fix "ambiguous overload" error when overloading operator<< (templated)?, when defining operator<<(std::ostream&, T) for all T, you overload it for types where an existing operator<< exists. Hence the ambiguous call:

os << n << ", ";
        ^-- recursively calls itself? or calls the overload provided by the Standard Library?

解决方案是使用SFINAE ,以确保仅为可迭代类型定义重载.由于基于范围的for循环的定义基于beginend,我们可以使用它来区分什么是Iterable:

The solution is to use SFINAE to ensure you define your overload only for iterable types. Since the definition of the range-based for loop is based on begin and end, we can use it to discriminate what is an 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;
}

(演示)

现在,std::cout << data会调用您的版本,而std::cout << '\n'会调用内置重载,因为对Iterable = char的替换失败:begin(char)未定义.

Now, std::cout << data calls your version and std::cout << '\n' calls the build-in overload since the substitution fails for Iterable = char: begin(char) is not defined.

这篇关于定义模板运算符&lt;&lt;对于可迭代的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-16 00:45