Тип преобразования в шаблон - PullRequest
0 голосов
/ 26 октября 2018

Я использую шаблонную функцию и не шаблонную.Код приведен ниже

#include <iostream>
using namespace std;

int maxOfTwo1(int a,int b)
{
    return a>b?a:b;
}
template<class T>
T maxOfTwo(T a,T b)
{
    return a>b?a:b;
}
int main()
{
    cout<<maxOfTwo1(3,6.3);//works fine
    cout<<maxOfTwo(3,6.3);//gives error
}

В первой функции 6.3 преобразуется в 6, но кто-нибудь может объяснить, почему этого не происходит и во второй функции?Вторая функция работает так же, просто имея шаблон.

Ответы [ 2 ]

0 голосов
/ 26 октября 2018

В вашем первом случае тип параметров известен ( int ), и аргументы преобразуются в этот тип ( int ), который корректно сформирован.

Во втором случае компилятор должен вывести T , но он заканчивается конфликтующими выводами и, следовательно, завершается неудачей.

Мы можем видеть это из [temp.deduct.type] p2 , который говорит (выделено мое):

В некоторых случаях вычет выполняется с использованием одного набора типов P и A, в других случаях будет набор соответствующих типов P и A. Вычитание типа выполняется независимо для каждой пары P / A, и выводимые значения аргумента шаблона затем объединяются. Если выведение типа не может быть выполнено для какой-либо пары P / A, или если для любой пары вычет приводит к более чем одному возможному набору выводимых значений, или если разные пары дают разные выведенные значения , или если какой-либо шаблон Аргумент не остается ни выведенным, ни явно заданным, Сбой вывода аргумента шаблона.

Определения P и A можно найти в [temp.deduct.call] p1 :

Вывод аргумента шаблона выполняется путем сравнения каждого типа параметра шаблона функции (назовите его P) с типом соответствующего аргумента вызова (назовите его A), как описано ниже. Если удаление ссылок и cv-квалификаторов из P дает std :: initializer_list для некоторого P ', а аргумент является списком инициализатора ([dcl.init.list]), то вместо этого для каждого элемента списка инициализатора выполняется удержание, принимая P 'как тип параметра шаблона функции и элемент инициализатора в качестве аргумента. В противном случае аргумент списка инициализатора приводит к тому, что параметр считается неделедированным контекстом ([temp.deduct.type]).

max66 дал несколько возможных решений, то есть с использованием различных параметров шаблона в сочетании с common_type.

0 голосов
/ 26 октября 2018

Конфликт дедукции.

Дано

template<class T>
T maxOfTwo(T a,T b)
{
    return a>b?a:b;
}

Если вы позвоните maxOfTwo(3,6.3), первое значение будет int; второй - float.

Компилятор должен вывести один тип T и не знать, если выбрано int или float.

Случай maxOfTwo1() отличается тем, что тип аргумента фиксируется на int, а компилятору просто нужно преобразовать значение float в значение int.

Если вы можете использовать хотя бы C ++ 14, вы можете решить, используя два типа шаблона и возвращаемый auto тип

template <typename T1, typename T2>
auto maxOfTwo (T1 a, T2 b)
 { return a>b?a:b; }

В C ++ 11 немного более многословно и менее элегантно

template <typename T1, typename T2>
auto maxOfTwo (T1 a, T2 b) -> decltype( a>b ? a : b )
 { return a>b?a:b; }

или вы можете использовать std::common_type (как предложено Якком)

template <typename T1, typename T2>
typename std::common_type<T1, T2>::type maxOfTwo (T1 a, T2 b)
 { return a>b?a:b; }

В противном случае вы можете явно указать правильный тип, вызывая функцию

maxOfTwo<int>(3, 6.3);
...