You have to tell the compiler which version to use. In C++, you can do it three ways.
Explicitely differentiate the calls by typing
You somewhat cheated because you sent an integer to a function waiting for a char, and wrongly sent the number six when the char value of '6' is not 6 but 54 (in ASCII):
std::string mul(char c, int n) { return std::string(n, c); }
std::string s = mul(6, 3); // s = "666"
The right solution would be, of course,
std::string s = mul(static_cast<char>(54), 3); // s = "666"
This was worth mentioning, I guess, even if you did not want the solution.
Explicitely differentiate the calls by dummy pointer
You can add a dummy parameter to each functions, thus forcing the compiler to choose the right functions. The easiest way is to send a NULL dummy pointer of the type desired for the return:
int mul(int *, int i, int j) { return i*j; }
std::string mul(std::string *, char c, int n) { return std::string(n, c); }
Which can be used with the code:
int n = mul((int *) NULL, 6, 3); // n = 18
std::string s = mul((std::string *) NULL, 54, 3); // s = "666"
Explicitely differentiate the calls by templating the return value
With this solution, we create a "dummy" function with code that won't compile if instanciated:
template<typename T>
T mul(int i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
You'll note this function won't compile, which is a good thing because we want only to use some limited functions through template specialization:
template<>
int mul<int>(int i, int j)
{
return i * j ;
}
template<>
std::string mul<std::string>(int i, int j)
{
return std::string(j, static_cast<char>(i)) ;
}
Thus, the following code will compile:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>(54, 3); // s = "666"
But this one won't:
short n2 = mul<short>(6, 3); // error: assignment of read-only variable ‘k’
Explicitely differentiate the calls by templating the return value, 2
Hey, you cheated, too!
Right, I did use the same parameters for the two "overloaded" functions. But you did start the cheating (see above)...
^_^
More seriously, if you need to have different parameters, then you will to write more code, and then have to explicitely use the right types when calling the functions to avoid ambiguities:
// For "int, int" calls
template<typename T>
T mul(int i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
template<>
int mul<int>(int i, int j)
{
return i * j ;
}
// For "char, int" calls
template<typename T>
T mul(char i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
template<>
std::string mul<std::string>(char i, int j)
{
return std::string(j, (char) i) ;
}
And this code would be used as such:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>('6', 3); // s = "666"
And the following line:
short n2 = mul<short>(6, 3); // n = 18
Would still not compile.
Conclusion
I love C++...
:-p