оператор перегрузки << для массивов - PullRequest
12 голосов
/ 29 января 2012

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

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

Ответы [ 2 ]

3 голосов
/ 29 января 2012

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

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

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

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

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

1 голос
/ 29 января 2012

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...