Ответ 1
Первый вызов выбирает специализацию шаблона функции - потому что это лучшее совпадение.
Обозначим обе перегрузки:
template<size_t N> void cm(const char (&h)[N]) // (1) - the specialization
{std::cout << " const (&)[N] " << endl;}
void cm(const char * h) // (2)
{cout << " const char * " << endl;}
Для (1), car
привязывается к ссылке. Это преобразование идентичности 1.
Для (2) после преобразования от матрица к указателю car
, что дает char*
2 необходимо выполнить квалификационное преобразование, чтобы char*
становилось char const*
, Это теперь вызывает это:
Стандартная последовательность преобразования
S1
является лучшей последовательностью преобразования, чем стандартная последовательность преобразованияS2
, если
S1
- это правильная подпоследовательностьS2
(сравнение последовательностей преобразования в канонической форме, определенных в 13.3.3.1.1, , исключая любые Преобразование Lvalue; последовательность преобразования идентичности рассматривается как подпоследовательность любого нетождественного преобразования последовательность) или, если это не так,- [...]
Преобразование от массива к указателю является преобразованием Lvalue, поэтому оно не рассматривается здесь - так же, как и во втором примере. Квалификационная конверсия имеет свою собственную категорию: Квалификационная корректировка. Поэтому преобразование в параметр (1) является подпоследовательностью преобразования в параметр (2): первое является преобразованием идентичности, а второе - квалификационным преобразованием, и согласно вышеприведенному абзацу преобразование идентичности является подпоследовательностью любое преобразование без идентичности. Итак, выбрано (1).
Как вы уже упоминали, во втором случае конверсии одинаково хороши; Вышеприведенная цитата не работает, поскольку преобразование в (2) s параметр не является подпоследовательностью преобразования в параметр (1). Следовательно, применяется [over.match.best]/1.
Учитывая эти определения, жизнеспособная функция
F1
определяется как лучше, чем другая жизнеспособная функцияF2
, если для всех аргументов i, ICSi (F1) не хуже схемы преобразования, чем ICSi (F2), а затем
- для некоторого аргумента j, ICSj (F1) является лучшей последовательностью преобразования, чем ICSj (F2), или, если не это,
- контекст представляет собой инициализацию с помощью пользовательского преобразования [...], или, если это не так,
F1
- это функция без шаблона, аF2
- специализированная функция шаблона,
Итак, (2) выбирается один. Если шаблон функции не был шаблоном, а функцией с параметром char const (&)[8]
, вызов был бы неоднозначным как правильно говорит Кланг.
1 [over.ics.ref]/1:
Когда параметр ссылочного типа напрямую связывается (8.5.3) с выражение аргумента, неявная последовательность преобразования - это тождество преобразование, если выражение аргумента не имеет тип, который является производный класс типа параметра, и в этом случае неявный Последовательность преобразования представляет собой преобразование с производной базой (13.3.3.1).
[dcl.init.ref]/5 (что в 8.5.3):
Во всех случаях, кроме последнего (т.е. создания и инициализации временный из выражения инициализатора), ссылка называется привязать непосредственно к выражению инициализатора.
2 [conv.array]:
lvalue или rvalue типа "массив
N T
" или "массив неизвестных bound ofT
" может быть преобразован в prvalue типа "указатель наT
". Результатом является указатель на первый элемент массива.
T
может быть cv-квалифицированным, и так будет тип получателя. Здесь T
является просто char
, поэтому указатель имеет указатель типа на char
= > char*
.