Templates: Return different types of data.

Hello!
I was reading the following tutorial and I have a question.
http://www.cplusplus.com/doc/oldtutorial/templates/

In the following code, I tried to change a little bit a code showed in the tutorial, how can I return different type of data depending on the smaller value?
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

template<typename T, typename U, typename R>
R getSmaller(T x, U y)
{
	return ((x < y) ? x : y);
}

int main(int argc, const char* argv[])
{	
	std::cout << getSmaller(7, 2.89) << std::endl;
	return 0;
}


Error message:
1
2
3
4
5
6
7
8
9
10
11
[rob@archrob ~]$ g++ -o test main.cpp 
main.cpp: In function ‘int main(int, const char**)’:
main.cpp:11:33: error: no matching function for call to ‘getSmaller(int, double)’
  std::cout << getSmaller(7, 2.89) << std::endl;
                                 ^
main.cpp:4:3: note: candidate: ‘template<class T, class U, class R> R getSmaller(T, U)’
 R getSmaller(T x, U y)
   ^~~~~~~~~~
main.cpp:4:3: note:   template argument deduction/substitution failed:
main.cpp:11:33: note:   couldn't deduce template parameter ‘R’
  std::cout << getSmaller(7, 2.89) << std::endl; 
You can't. A template must be fully resolved during compile time, when the value of
 
x < y
is not yet known. The type of the expression getSmaller(7, 2.89) must be fully known before the compiler can generate code for it. In your sample code, the type is unknown because the compiler is not able to infer the value of the template parameter R from the call's arguments, and you haven't passed it explicitly as a template parameter.

There are ways in C++ to make a function return different run time types (which should be subtypes of a single compile time type), but templates cannot do it.
Furthermore, the ?: operator is a "gotcha" of the C++ language when it comes to dealing with two different types.
https://stackoverflow.com/questions/32251419/c-ternary-operator-conditional-operator-and-its-implicit-type-conversion-r

Long story short: Just avoid the ?: operator from operating on different return types unless you know what you're doing. Use if/else. (This is a separate issue from what helios already discussed; you can't use a template in this way.)
Ok, I understand.

Thank you guys!
I wander, if we are sure we are only dealing with ints and floats, if we could play some nasty trick like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>

template <typename T, typename U>
auto getSmaller(T x, U y) -> decltype( x + y )
{
    if(x <= y) { return x; }
    return y;
}


int main()
{
    std::cout << getSmaller(7, 2.89) << std::endl;
    return 0;
}


Anyway, if we were happy with such dirty code, I think we could also stick to the original one:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

template<typename T, typename U, typename R>
auto getSmaller(T x, U y) -> decltype( x + y )
{
    return x < y ? x : y;
}


int main()
{
    std::cout << getSmaller(7, 2.89) << std::endl;
    return 0;
}


In Ganado’s link I can read:
If both operands are of arithmetic or enumeration types, the usual arithmetic conversions (covered in Arithmetic Conversions) are performed to convert them to a common type.

So it looks the same conversion as the one that will be performed in the decltype statement.

Is this that bad?
In the case of doubles and floats, no I wouldn't say it's bad. But I remember past posts about dynamic types being cast incorrectly or something of that nature.
@Ganado, thank you anyway for reading my code.
Registered users can post here. Sign in or register to post.