Overload operator with pattern but not overridden
I want to define specialization operator<<
using a template, but I do not want it to break the behavior of this operator if it is already defined for some data type.
enum State {Open, Locked};
enum Input {Coin, Push};
std::string ToString(State c){
switch (c) {
case Locked : return "Locked";
case Open : return "Open";
}
}
std::string ToString(Input c){
switch (c) {
case Coin : return "Coin";
case Push : return "Push";
}
}
template<typename T> //obviously, a bad idea
std::ostream& operator<<(std::ostream& s, T c) {
return s<<ToString(c);
}
later in the code I would like to use:
int main() {
std::cout<<Coin<<std::endl;
std::cout<<Open<<std::endl;
std::cout<<std::string("normal string")<<std::endl;
}
Unsurprisingly, the above is a compilation error:
error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘std::string {aka std::basic_string<char>}’)
std::cout<<std::string("normal string")<<std::endl;
(much more)
Q: How do I tell the compiler to ignore the template if the function / operator already has a definition?
source to share
To add to @songyuanyao's answer , do two more things:
- Wrap your code in a namespace.
- Fully qualify the identifier in
decltype
the namespace. That is, something likedecltype(MyNS::ToString(std::declval<T>()))
.
Your print statements will still run ADL aware, but you won't run search rules if your statement is somehow a candidate with a type that it also defines ToString
in a different namespace. 1
1 If you have templates in your namespace, ADL will also consider their parameter namespaces. Which may put you in the good of a different definition ToString
during an unqualified search.
source to share