2016-06-03 3 views
1

Я написал простой шаблон, чтобы найти наименьшее число в списке аргументов.Когда мне нужно указать тип шаблона

template<typename T> 
T smallerList(T a, T b) { 
    std::cout << "a= " << a << " b= " << b << std::endl; 
    return a < b ? a : b; 
} 

template<typename T, typename... Rest> 
T smallerList(const T& param0, const Rest&... rest) { 
    T temp = smallerList(rest...); 
    return param0 < temp ? param0 : temp; 
} 

int main() 
{ 
     // Works, returns "3" 
     std::cout << "Smaller: " << smallerList(4, 5, 6, 3, 7) << std::endl; 

     // Sort of works, returns "2". Should be "2.14". 
     std::cout << "Smaller: " << smallerList(3.14, 43534, 100.2, 3.13, 2.14) << std::endl; 

} 

По какой-то причине второй вызов функции возвращает 2 вместо 2.14. Почему это происходит?

Я напечатал промежуточные значения переменных, и они верны. Кажется, что неявное преобразование происходит, когда smallList возвращается.

я был в состоянии решить эту проблему, изменив строку

T temp = smallerList(rest...); 

в

T temp = smallerList<T>(rest...); 

После этого изменения функция печатает 2.14, как и ожидалось.

Мой вопрос: Почему мне нужно указать тип? Я думал, что функции шаблонов «созданы» для каждого вызываемого типа?

+0

Хорошо, какой должен быть тип возврата 'smallList (3.14, 43534, 100.2, 3.13, 2.14)' и почему? Можете ли вы придумать критерий? – luk32

ответ

2

Хорошо, я не знаю, как вам действительно помочь, потому что я не знаю, какую именно логику вы хотите иметь. Но у вас VARIADIC шаблона позволяет смешивать тип, и в вашем 2-й векторе, вы передаете одно целое число - 43534, поэтому, когда 2.14 назад распространяется, когда рекуррентные откатывает вы получите что-то вроде

return (int)(43534 < 2.14? 43534 : 2.14);

Поскольку 43534 будет param0 , и вы берете возвращаемый тип param0, а 2.14 преобразуется в 2. Затем он преобразуется обратно в float, но вы его не видите.

Вам либо нужно проверить, одинаковы ли параметры, либо придумать какую-либо логику для продвижения ваших аргументов. Не то чтобы он работает, как вы ожидаете, если вы используете 43534.0, потому что он больше не будет int.

EDIT:

T temp = smallerList<T>(rest...); это не помогает вам, это изменяет поведение, заставляя бросок на каждый аргумент типа 1-го аргумента. Ну, это становится более последовательным. Но попробуйте:

smallerList(7, 10.5, 10, 3.13, 2.14) 

Он сломается. Я не на 100% уверен, почему, но я думаю, что это не могло соответствовать концу рекурсии, потому что он будет искать smallerList(int, float), и ваш шаблон терминатора не будет соответствовать.

Вам нужно будет что-то вроде:

template<typename T, typename U> 
T smallerList(T a, U b) { 
    std::cout << "a= " << a << " b= " << b << std::endl; 
    return a < b ? a : b; 
} 

Он также сбрасывает 2-й тип, так что вы будете иметь преобразования типов, но если ваша цель состоит в том, чтобы сохранить тип 1-го аргумента он соответствует.

+0

Ах, конечно. Я не заметил беззнакового в списке парных. Я ожидал, что вариационный шаблон будет иметь один тип, но вместо этого создается новая функция smallList для каждого значения в списке. Тип не распространяется. – Maurice

+0

Да, вы должны изменить определение своего шаблона терминатора, чтобы позаботиться о смешанных типах, поскольку текущая версия не будет соответствовать, если тип 1-го аргумента отличается от типа последнего. – luk32

+0

'auto' из C++ 14, или' std :: common_type' может помочь. – Jarod42