2012-01-29 3 views
12

Сегодня я думал, что это будет хорошая идея, чтобы перегрузить 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'; 
} 

Действительно, это печатает {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' 

Это действительно озадачивает. Почему компилятор даже рассматривает перегрузку long int, когда нет конверсии с const char[13] в long int?

Вариации этого сообщения об ошибке появляются для long unsigned int, short int, short unsigned int, int, unsigned int, long long int и long 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]) 

Но Меня все еще озадачивает вопрос, почему компилятор рассматривал числовые типы в качестве кандидатов.

ответ

3

Первый этап разрешения перегрузки - определение жизнеспособных функций, которые могут принимать количество предоставленных аргументов (полностью игнорируя типы). (См., Например, 13.3.2 [over.match.viable]).

Тогда любые необходимые преобразования считаются определяющими, что является уникальной лучшей жизнеспособной функцией.

В этом случае нет такого уникального лучшего (есть два одинаково хороших кандидата).

Сообщение об ошибке может просто рассказать вам два неоднозначных случая. Но я думаю, что они пытаются помочь, показывая, почему все другие жизнеспособные функции потеряны. Иногда это полезно, когда вы не можете понять, почему функция, которую вы хотите вызвать, не рассматривалась.

Но я согласен, что в основном это всего лишь шум, особенно для таких функций, как operator << или operator >> (или даже operator []), которые имеют много перегрузок.

1

Компилятор правильно отклоняет программу. Я думаю, что ключ в том, что ваша перегрузка и ostream::operator<<(char const *) оба появляются в сообщении об ошибке. Интегральные, вероятно, красная селедка ... вы можете указать reinterpret_cast указатель (или строковый литерал) на long int (§5.2.10/4), но это, безусловно, не стандартное преобразование. Возможно, компилятор просто пытается быть полезным, предоставляя вам больше перегрузок.

Учитывая вашу перегрузку и член ostream, разрешение перегрузки происходит просто потому, что между ними нет правила приоритета (§13.3.1.2). Таким образом, поскольку перегрузка члена char const * является единственной, с которой вы можете столкнуться, ваше исправление кажется подходящим.

+0

'std :: ostream' - это ссылка на класс. – Mankarse

Смежные вопросы