No Automatic Cast from `int` to `float` with Template Function
Asked Answered
C

6

13

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;
}
Convertible answered 2/10, 2015 at 19:30 Comment(2)
introduce class T2 or make second non-deducible with decltype(first) second ?Kindness
Interesting scenario though. I think a default compiler switch should have been implemented to handle such cases...Whirlabout
K
16

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.
Kyser answered 2/10, 2015 at 19:35 Comment(1)
You should explain how that magical second example works, for when Piotr's comment is inevitably nuked.Bobbee
C
9

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...

Calla answered 2/10, 2015 at 19:34 Comment(0)
P
4

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)
Pernickety answered 2/10, 2015 at 19:34 Comment(1)
T is undeclared so cannot be used as the return type, and writing the return type correctly then T1 and T2 are different is possible, but complicated enough (unless using auto as in other answers) that it probably needs to be addressed for your answer to really be useful to the OP.Barbbarba
H
3

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;
}
Halloween answered 2/10, 2015 at 19:36 Comment(4)
thanks for your answer. note that T is undefined in your code.Convertible
@Convertible thanks, that was a simple copy/paste error. I've also fleshed out the answer with auto.Halloween
It's new c++14 feature which I can't use it. thanks anyway and I give your effort +1 :]Convertible
Which type to return? decltype(first+second) obviously. or however the hell you explicitly write that.Unfreeze
R
2

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;
}
Rhaetian answered 3/10, 2015 at 0:13 Comment(0)
V
1

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;
}
Vanhomrigh answered 2/10, 2015 at 19:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.