The problem you see is that template type inference requires a perfect match for all type inference. In your case, you have a template that takes a single argument of type T , which is both scalar and matrix types. When compilers see the operation: 5 * m1 , it outputs T == int for the first argument, but T == double for the second argument, and type inference is not performed.
There are several approaches around this, as suggested, you can add a second template argument:
template <typename T, typename S> Matrix<T> operator*( Matrix<T> m, S scalar ) { return m*=scalar; }
[Note: both arguments are by value, the second is because for arithmetic types it is more efficient and idiomatic for passing by value; the first one, because by moving the copy to the function interface, you allow the compiler to delete the copies]. This approach is simple, but will generate one operator* for each combination of S and T in the program, even if the actual multiplication in operator*= always performed by T
Another approach is to fix the type of scalar that you want to propagate, for example, make it double , generating only one operator* per T type that multiplies:
template <typename T> Matrix<T> operator*( Matrix<T> m, double scalar ) { return m*=scalar; }
There is one operator* in this approach that takes double as an argument. As in the previous example, a scalar may need to convert two types (say, you multiply Matrix<int> by 5 ), then convert 5 to double , which will then be converted back to int to match the operator*= signature.
The third approach is to create a non-templated function that takes your Matrix and another argument of the same type. This will be closest to your source code, with a slight advantage that, not being a template, it will allow conversions for the scalar argument. Theoretically, you can define all such functions yourself:
Matrix<int> operator*( Matrix<int>, int ) { ... } Matrix<double> operator*( Matrix<double>, double ) { ... }
But it becomes a maintenance problem very easily. Fortunately, the language has a function that allows you to outline all these non-template functions. Although the syntax may not be the most natural. You just need to declare a free function as a friend of your template and define it inside the class template definition:
template <typename T> class Matrix {
Since we are inside the Matrix class template, we can use Matrix (without arguments) to refer to the current instance ( Matrix<int> , Matrix<double ...) [This may not seem very important, but it is important, it is important to understand when Matrix refers to the template, and when it refers to the class generated from the template]. The second argument to the function is T Again, this is not a generic T the class template, but the current instance type ( int , double ...).
The language allows you to define a friend function within a class that has a declaration and that will define a function at the namespace level, although the declaration will only be found by searching for Dependent Lookup arguments.
Whenever you instantiate a specific instance of your template (for example, Matrix<int> ) and call the operator, the compiler will generate a free function for you. Since this function is not a template, it allows you to convert arguments, and thus for Matrix<int> m it will allow you to call m * 5. by converting 5. to int .