【问题标题】:overloading operator<< for arrays为数组重载运算符<<
【发布时间】:2012-02-21 13:59:50
【问题描述】:

今天我认为为 C 样式数组重载 operator&lt;&lt; 是个好主意:

template<typename T, size_t N>
std::ostream& operator<<(std::ostream& os, T(&a)[N])
{
    os << '{' << a[0];
    for (size_t i = 1; i < N; ++i)
    {
        os << ',' << ' ' << a[i];
    }
    os << '}';
    return os;
}

int main()
{
    int numbers[] = {2, 3, 5, 7, 11, 13, 17, 19};
    std::cout << numbers << '\n';
}

确实,这很好地打印了{2, 3, 5, 7, 11, 13, 17, 19}。但是,通过提供该重载,我无法再打印字符串文字了:

    std::cout << "hello world\n";

error: ambiguous overload for 'operator<<' in 'std::cout << "hello world\012"'
note: candidates are:

note: std::basic_ostream<_CharT, _Traits>::__ostream_type&
std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _
Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_
type = std::basic_ostream<char>] <near match>

note:   no known conversion for argument 1 from 'const char [13]' to 'long int'

这真是令人费解。为什么编译器一开始就没有从const char[13]long int 的转换,还要考虑long int 重载?

long unsigned intshort intshort unsigned intintunsigned intlong long intlong long unsigned int 出现此错误消息的变体。

(其他候选人有const void*const char*const _CharT*,还有我自己的模板。)


我通过只为非字符类型提供模板解决了这个问题:

template<typename T, size_t N>
typename std::enable_if<
    !std::is_same<typename std::remove_cv<T>::type, char>::value,
std::ostream&>::type operator<<(std::ostream& os, T(&a)[N])

但我仍然对为什么编译器将数字类型视为候选者的问题感到困惑。

【问题讨论】:

    标签: c++ arrays string templates operator-overloading


    【解决方案1】:

    重载决策的第一阶段是识别可行的函数,这些函数可以接受提供的参数数量(完全忽略类型)。 (参见例如 13.3.2 [over.match.viable])。

    然后考虑任何需要的转换以确定哪个是唯一的最佳可行函数。

    在这种情况下,没有这样独特的最佳人选(有两个同样优秀的候选人)。

    错误消息可能只是告诉您两个模棱两可的情况。但我认为他们试图通过展示为什么所有其他可行的功能都失败了来提供帮助。有时这很有用,当您无法弄清楚为什么没有考虑要调用的函数时。

    但我同意大多数情况下这只是很多噪音,尤其是对于像 operator &lt;&lt;operator &gt;&gt;(甚至是 operator [])这样有很多重载的函数。

    【讨论】:

      【解决方案2】:

      编译器拒绝程序是正确的。我认为关键是您的重载和ostream::operator&lt;&lt;( char const * ) 都出现在错误消息中。不可或缺的可能是一个红鲱鱼......你可以reinterpret_cast一个指针(或字符串文字)到long int(§5.2.10/4),但这肯定不是标准转换。也许编译器只是想通过给你更多的重载来提供帮助。

      鉴于您的重载和 ostream 成员,重载解析失败只是因为没有优先规则可以在它们之间做出决定(第 13.3.1.2 节)。因此,由于 char const * 成员重载是唯一可能与您发生冲突的成员,因此您的修复似乎是合适的。

      【讨论】:

      • std::ostream 是一个类的引用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-14
      • 2016-08-30
      • 1970-01-01
      • 1970-01-01
      • 2018-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多