Краткий ответ: Код в порядке, и MSVC выдает ложное предупреждение.
MSVC и g ++ имеют ошибки в сопоставлении аргументов не типового шаблона, но они выбирают правильный дляВаш конкретный пример.
Длинный ответ: Можно иметь перегруженные шаблоны функций с нетиповыми параметрами шаблона.
Однако совпадение template-аргумент к объявлению шаблона не работает, как и следовало ожидать (во всяком случае, мне).ВСЕ соответствующие шаблоны вводятся в разрешении перегрузки.На любом этапе он не предпочитает «точное совпадение».
Согласно C ++ 17 [temp.arg.nontype /] 2, преобразованные константные выражения допускаются.Это означает, например:
42
соответствует int
и unsigned int
. 42u
соответствует int
и unsigned int
. 1u
соответствует unsigned int
, int
и bool
.
Обратите внимание, что преобразованное константное выражение не может содержать сужающее преобразование, а int
до bool
сужается, если толькозначение является постоянным выражением значения 0
или 1
.Так что 42
не соответствует bool
.(Ссылка: C ++ 17 [expr.const] / 4).
Если бы у нас была следующая настройка:
template<unsigned int V> void g() {}
template<bool B> void g() {}
, то правильное поведение:
g<42>()
звонки g<unsigned int>
. g<1>()
неоднозначны. g<1u>()
неоднозначны.
MSVC 2017 и g ++ 7,8 все неверно позволяют g<42>
соответствовать g<bool>
, и сообщают g<42>
как неоднозначные.
MSVC выдает предупреждение, которое вы видите при генерации недопустимого соответствия;g ++ не дает никакой диагностики вообще.Если мы удалим перегрузку unsigned int
, то g ++ автоматически примет недействительный код без диагностики.
В вашем коде есть неконстантный ссылочный параметр lvalue:
template<unsigned int V> void h(unsigned int&) {}
template<bool B> void h(bool&) {}
Это имеет значение, потому что разрешение перегрузки может сделать выбор на основе аргумента функции.Для вызова:
unsigned int m;
h<1u>(m);
тогда обе перегрузки h
вводятся в разрешение перегрузки, однако тогда h<unsigned int>
выигрывает, потому что h<bool>(m)
будет недействительным.
Как обсуждалось выше,Вызов h<42>(m);
выигрывает на первом этапе, потому что это не может соответствовать h<bool>
;но в MSVC ++ (и g ++) он неправильно разрешает выполнение h<bool>
на этом этапе, но сокращает его позже, как в случае h<1u>
.