Что нужно помнить о шаблонах, так это то, что они не сделают для вас преобразование. Все, что они делают, это пытаются выяснить типы вещей, и если это сопряжено с параметрами шаблона, то оно вытеснит функцию и вызовет ее.
В вашем случае, когда вы делаете
foo_value + 1.0
компилятор работает нормально, давайте посмотрим, есть ли у нас operator +
, который будет работать для этого. Находит
template<typename T>
foo<T> operator+(foo<T> a, foo<T> b)
{
return foo<T>(a.val + b.val);
}
и затем он пытается выяснить, что такое T
, чтобы он мог выделить конкретную функцию. Он смотрит на foo_value
, видит, что это foo<double>
, поэтому он говорит, что для первого параметра T
должен быть double
. Затем он смотрит на 1.0
и все в порядке, у меня есть double
, и именно тогда вы сталкиваетесь с проблемой. Компилятор не может определить, что T
должно быть для b
, потому что он ожидает foo<some_type>
, но вместо этого получил double
. Поскольку он не может определить тип, ваш код не может быть скомпилирован.
Чтобы получить желаемое поведение, вам нужно добавить
template<typename T>
foo<T> operator+(foo<T> a, T b)
{
return foo<T>(a.val + b);
}
Что позволяет добавить T
к foo<T>
, или еще лучше
template<typename T, typename U>
foo<T> operator+(foo<T> a, U b)
{
return foo<T>(a.val + b);
}
Что позволяет вам добавить что-либо в foo<T>
(foo<double> + int
, например, если первая версия этого не допустит)