Your original code does not compile
The code that you showed us
#include <iostream>
#include <string>
class ADDON {
std::string s;
public:
ADDON() {
s = "";
}
ADDON(std::string in) {
s = in;
}
ADDON(const char in[]) {
s = in;
}
void operator=(const std::string in) {
s = in;
}
std::string getString() {
return s;
}
};
template<typename T>
void print_to_default_file(T &obj, ADDON addon = "")
{ std::cout << "first overload\n"; }
template<typename T>
void print_to_default_file(T &obj, std::string objS)
{ std::cout << "second overload\n"; }
int main()
{
print_to_default_file("test","where will I go");
}
does not compile (online output) with the following error
prog.cpp: In function ‘int main()’: prog.cpp:39:52: error: call of
overloaded ‘print_to_default_file(const char [5], const char [16])’ is
ambiguous prog.cpp:39:52: note: candidates are: prog.cpp:30:6: note:
void print_to_default_file(T&, ADDON) [with T = const char [5]]
prog.cpp:34:6: note: void print_to_default_file(T&, std::string) [with
T = const char [5]; std::string = std::basic_string]
The reason is that name lookup and argument deduction find 2 candidates: the first overload requires a const char*
to ADDON
conversion, and the second overload a const char*
to std::string
conversion. Both conversion sequences are equally good matches and overload resoution is ambiguous and your program ill-formed.
A simple fix
Simply change the second overload to take a const char*
as parameter (and not as char*
, which cannot bind against string literals) and it will be the best match for raw string literals as argument
template<typename T>
void print_to_default_file(T &obj, const char* objS) // but NOT char* objS
{ std::cout << "second overload\n"; }
You will now get the second overload (online output). To select the first overload, simply call the ADDON
constructor in the parameter list
int main()
{
print_to_default_file("test", ADDON("where will I go"));
}
Note that this will call the ADDON(const char[])
constructor and not the ADDON(std::string)
one, since the latter will require a user-defined conversion (online output).
The proper fix
It is extremely dangerous to have non-explicit single argument constructors. Always use explicit
keyword around such functions.
class ADDON {
std::string s;
public:
ADDON() {
s = "";
}
explicit ADDON(std::string in) {
s = in;
}
explicit ADDON(const char in[]) {
s = in;
}
void operator=(const std::string in) {
s = in;
}
std::string getString() {
return s;
}
};
This will also call the second overload (online output), because the ADDON
overload does not explicitly call any constructor. To select the first overload, again call the ADDON
constructor in the parameter list.