Today I thought it would be a nice idea to overload operator<< for C style arrays:
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';
}
Indeed, this prints {2, 3, 5, 7, 11, 13, 17, 19} nicely. However, by providing that overload, I cannot print string literals anymore:
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'
This is really puzzling. Why does the compiler even consider the long int overload when there is no conversion from const char[13] to long int in the first place?
Variations of this error message appear for long unsigned int, short int, short unsigned int, int, unsigned int, long long int and long long unsigned int.
(Other candidates are const void*, const char* and const _CharT*, and my own template.)
I solved the problem by providing the template for non-char types only:
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])
But I'm still baffled by the question why the compiler considered the numeric types as candidates.