C++ Шаблонная специализация по типу нетипичного параметра
Допустимо ли иметь варианты одной и той же шаблонной функции, которые различаются по типу нетипичного члена?
template<typename T, unsigned int V>
void f(unsigned int& v) { v = V; }
template<typename T, bool B>
void f(bool& b) { b = B; }
Намерение состоит в том, чтобы можно было
unsigned int meaningOfLife;
f<sometype, 42>(meaningOfLife);
bool areYouAlive;
f<sometype, true>(areYouAlive);
clang и gcc молчат, но отчеты MSVC
warning C4305: 'specialization': truncation from 'int' to 'bool'
Я бы хотел избежать указания типа константы:
f<sometype, bool, true>
и хотим убедиться, что постоянное значение и целевое значение совпадают.
---- Макве ----
#include <iostream>
template<unsigned int V>
void f(unsigned int& v) { v = V; }
template<bool B>
void f(bool& b) { b = B; }
int main()
{
unsigned int u { 0 };
bool b { false };
f<42>(u);
f<true>(b);
std::cout << u << b;
}
Пример Rextester: http://rextester.com/VIGNP16100
Warning(s):
source_file.cpp(14): warning C4305: 'specialization': truncation from 'int' to 'bool'
/LIBPATH:C:\boost_1_60_0\stage\lib
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x64
421
1 ответ
Краткий ответ: код в порядке, и MSVC выдает ложное предупреждение.
MSVC и g ++ имеют ошибки в сопоставлении аргументов не типового шаблона, но они выбирают правильный для вашего конкретного примера.
Длинный ответ: нормально иметь перегруженные шаблоны функций с нетиповыми параметрами шаблона.
Однако сопоставление аргумента шаблона с объявлением шаблона не работает, как можно было ожидать (во всяком случае, для меня). ВСЕ соответствующие шаблоны вводятся в разрешении перегрузки. На любом этапе он не предпочитает "точное совпадение".
Согласно 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>
дело.