demorge
demorge

Reputation: 1117

Small annoyance with template function

Ok, let's say I have a function like this

template <typename T>
void Func(std::vector<T> x, T alpha = 1)
{
    // ... do stuff
}

and I would like to use it with a complex type, like this

std::vector<std::complex<double>> x;
Func(x, 5.5);

Then the compiler complains (VS2010) that template parameter 'T' is ambiguous because it could be 'double' or 'std::complex<double>'. Obvious fix, call it like this

Func(x, std::complex<double>(5.5));

but, that, I don't want. Why can't it be converted to a complex type automatically?

Upvotes: 3

Views: 115

Answers (4)

metal
metal

Reputation: 6332

If you don't like identity helpers and just want it to be convertible, try this:

template <typename T, typename U>
void Func(const std::vector<T>& x, U alphaU = 1)
{
    const T alpha(alphaU); // Convert to T
    // ... do stuff
}

Update:

Re your comment: I tried it with several compilers at http://liveworkspace.org and this code builds fine for me:

#include <vector>
#include <complex>

template <typename T, typename U>
void Func(const std::vector<T>& x, U alphaU)
{
   const T alpha(alphaU); // Convert to T
   (void) x;
   (void) alpha;
}

template <typename T>
void Func(const std::vector<T>& x)
{
    Func( x, 1 );
}    

int main()
{
   std::vector<std::complex<double>> v(10);
   Func( v, 5.5 );
   Func( v );
}

Upvotes: 0

Pete Becker
Pete Becker

Reputation: 76458

If you need to have a default argument whose type is different from the contained type, just use two different types:

template <class T, class U>
void Func(vector<T> x, U y);

Upvotes: 1

mfontanini
mfontanini

Reputation: 21910

How about this?

template<typename T>
struct identity {
    typedef T type;
};

template <typename T>
void Func(std::vector<T> x, typename identity<T>::type alpha = 1)
{
    // ... do stuff
}

The second argument will not be involved in the template parameter deduction, the vector template argument will be used.

Upvotes: 3

Joseph Mansfield
Joseph Mansfield

Reputation: 110748

The reason it doesn't work is because the first argument causes T to be deduced as std::complex<double> whereas the second argument causes it to be deduced as double. It simply doesn't consider conversions when deducing arguments. Obviously, this makes the deduction ambiguous.

You can force the second argument type to be non-deducable with the help of an identity helper:

template <typename T>
struct identity { typedef T type; };

template <typename T>
void Func(std::vector<T> x, typename identity<T>::type alpha = 1)
{
    // ... do stuff
}

Upvotes: 4

Related Questions