重载operator << for arrays

fre*_*low 12 c++ arrays string templates operator-overloading

今天我认为operator<<为C样式数组重载是个不错的主意:

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';
}
Run Code Online (Sandbox Code Playgroud)

确实,这打印{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'
Run Code Online (Sandbox Code Playgroud)

这真是令人费解.为什么编译甚至考虑long int过载时,有没有转换从const char[13]long int摆在首位?

此错误消息的变化出现long unsigned int,short int,short unsigned int,int,unsigned int,long long intlong long unsigned int.

(其他候选人const void*,const char*const _CharT*和我自己的模板.)


我通过仅为非char类型提供模板来解决问题:

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])
Run Code Online (Sandbox Code Playgroud)

但是我仍然对编译器为什么认为数字类型作为候选者的问题感到困惑.

Ala*_*kes 3

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

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

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

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

但我同意,大多数情况下,这只是很多噪音,特别是对于像operator <<or operator >>(甚至operator []) 这样有很多重载的函数。