Question

This question stems from an answer I received yesterday. For the following function, I am getting the error couldn't deduce template parameter ‘V’ if both T and U are std::complex<double>. If T and U are different, the function compiles and works as intended.

template<class T, class U, class V>
auto operator*(const T a, const matrix<U> A) -> decltype(std::declval<T>()*std::declval<U>())
{
    matrix<V> B(A.size(1),A.size(2));
    for(int ii = 0; ii < B.size(1); ii++)
    {
        for(int jj = 0; jj < B.size(2); jj++)
        {
            B(ii,jj) = a*A(ii,jj);
        }
    }
    return B;
}

The usage is as follows:

std::complex<double> a1;
matrix<std::complex<double> > A1;
double a2;
matrix<std::complex<double> > A2;

/* ... */

matrix<std::complex<double> > B1 = a1*A1; // Compiler error
matrix<std::complex<double> > B2 = a2*A2; // Compiles and runs fine.

I should also mention I am compiling with g++ 4.7.3 and C++11 enabled.

EDIT:

A work around that I found is to also supply this function template:

template<class T>
matrix<T> operator*(const T a, const matrix<T> A)
{
    matrix<T> B(A.size(1),A.size(2));
    for(int ii = 0; ii < B.size(1); ii++)
    {
        for(int jj = 0; jj < B.size(2); jj++)
        {
            B(ii,jj) = a*A(ii,jj);
        }
    }
    return B;
}

With this addition, both cases above compile and run correctly.

Was it helpful?

Solution

I think there must be a another overload of operator* involved, because V cannot be deduced given the declaration:

template<class T, class U, class V>
auto operator*(const T a, const matrix<U> A)
  -> decltype(std::declval<T>()*std::declval<U>());

The only way to call this function is to specify V explicitly, e.g., operator*<int, long, long>(...).


Edit: Looking at the signature for operator*(T, matrix<T>) in the second code example, it would appear that your first code sample should read:

template<class T, class U>
auto operator*(const T a, const matrix<U>& A) -> matrix<decltype(a*A(0,0))>
{
    matrix<decltype(a*A(0,0))> B(A.size(1),A.size(2));
    for(int ii = 0; ii < B.size(1); ii++)
    {
        for(int jj = 0; jj < B.size(2); jj++)
        {
            B(ii,jj) = a*A(ii,jj);
        }
    }
    return B;
}

operator*(T,matrix<T>) should not be necessary as a special case.

OTHER TIPS

The problem is not that T and U are the same, but that there is noting in the function prototype mentioning the V type.

Considering you use V to declar B that you return, and that you define the return type as T()*U(), I wonder what matrix<V> should be.

I would expect B and the return type to be matrix<decltype(declval<T>()*declval<U>())>, with no V (that should not be in the parameter list)

I think if T and U are different another function is being called, because the compiler is right, V cannot be deduced, period. Even I can't deduce what you think that parameter should be. Here's proof that the second doesn't compile and run either, which means a different function is being called in that case. The obvious solution is to simply remove the class V template parameter type, and simply use the deduced type. Maybe you wanted something more like this?

Looking at your code again, the one that you say fails is complex * matrix, while the second is matrix*matrix. what other operator* are defined?


Unrelated, the three normal ways to accept parameters are T, const T&, or T&&. There's very little reason to have a const T parameter type. I believe you are missing a &?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top