Emadpres
Emadpres

Reputation: 3737

No Automatic Cast from `int` to `float` with Template Function

After years of coding in c++, today I was asked a simple question, but indeed I couldn't find its answer and so here I am guys.

Besides wondering why this error is happening, I want to know how I can solve below error by modifying just the template function (without changing the main() function)

template <class T>
T Add(T first, T second)
{
    return first + second;
}

int main()
{
    auto sample_1 = Add(1, 2); // Works
    auto sample_2 = Add(1.f, 2.f); // Works
    auto sample_3 = Add(1.f, 2); // Error: no instance matches the argument types: (double, int)
    return 0;
}

Upvotes: 13

Views: 2134

Answers (6)

KevinZ
KevinZ

Reputation: 3319

Why write your own function when the standard already provided them?

In c++11, you can use:

#include <functional>
int main()
{
    auto sample_1 = std::plus<float> () ( 1, 2 ); // Works
    auto sample_2 = std::plus<float> () ( 1.f, 2.f ); // Works
    auto sample_3 = std::plus<float> () ( 1.f, 2 ); // Works
    return 0;
}

In c++14:

#include <functional>
int main()
{
    auto sample_1 = std::plus<> () ( 1, 2 ); // Works
    auto sample_2 = std::plus<> () ( 1.f, 2.f ); // Works
    auto sample_3 = std::plus<> () ( 1.f, 2 ); // Works
    return 0;
}

Upvotes: 2

Mark Ransom
Mark Ransom

Reputation: 308392

The compiler is trying to deduce the template type that it can use to create a function that matches the signature. Since the parameters are different types, it's unable to do so.

You could specify the type explicitly:

auto sample_3 = Add<float>(1.f, 2);

But you say you don't want to do that.

You can change the function to take two template types:

template <class T1, class T2>
T1 Add(T1 first, T2 second)
{
    T1 p;
    p = first + second;
    return p;
}

But now you'll have to make an assumption about which type to return.

I've never tried to use auto as the return type, but apparently it works: http://ideone.com/1qO95w

template <class T1, class T2>
auto Add(T1 first, T2 second)
{
    auto p = first + second;
    return p;
}

Upvotes: 3

R Sahu
R Sahu

Reputation: 206667

Besides wondering why this error is happening,

When you call Add(1.f, 2), the first argument type is float and the second argument type is int.

The compiler has to convert either the first argument to an int or the second argument to a float. Since both of them will require a conversion, they are equally good candidates. One cannot be preferred over the other.

I want to know how I can solve below error by modifying just the template function

You can change the function template to:

template <class T1, class T2>
auto Add(T1 first, T2 second)
{
    return first + second;
}

or to (thanks @PiotrSkotnicki):

template <class T>
T Add(T first, decltype(first) second)
{
    return first + second;
}

In this case, the type of second is not deduced from the argument being passed to the function. Type of first is deduced from the first argument and the type of second is forced to be the same as the type of first.

Add(1.2f, 2);  // The first argument is deduced to be float
               // The second argument is forced to be float.

Add(2, 1.2f);  // The first argument is deduced to be int
               // The second argument is forced to be int.

Upvotes: 16

NathanOliver
NathanOliver

Reputation: 180935

When you have

template <class T>
T Add(T first, T second)

the type of first and second need to be the same. If you want to take two different types then you can add a second template parameter

template <class T1, class T2>
auto Add(T1 first, T2 second)

or for C++11

template <class T1, class T2>
auto Add(T1 first, T2 second) -> decltype(first + second)

Upvotes: 4

jpo38
jpo38

Reputation: 21514

I want to know how I can solve below error by modifying just the template function

Like that:

template <class T1, class T2>
T1 Add(T1 first, T2 second)
{
    T1 p;
    p = first + second;
    return p;
}

int main()
{
    auto sample_1 = Add(1, 2);
    auto sample_2 = Add(1.f, 2.f);
    auto sample_3 = Add(1.f, 2);
    return 0;
}

Upvotes: 1

Jarod42
Jarod42

Reputation: 217810

Just do:

template <class T1, class T2>
auto Add(T1 first, T2 second)
{
    return first + second;
}

As with unique T, it is deduced once as int, once as double...

Upvotes: 9

Related Questions