Специализация шаблона C ++ по типу нетипичного параметра - PullRequest
0 голосов
/ 24 мая 2018

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

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>

и хочу убедиться, что значение константыи целевое значение совпадает.

---- mcve ----

#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 Ответ

0 голосов
/ 24 мая 2018

Краткий ответ: Код в порядке, и 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>.

...