Simple solution using manual overloading for each type which you want to print directly:
Define your first implementation which calls T::print()
. Use overloading to specify alternative implementations for all types which don't have this function. I don't recommend this solution, but it's very easy to understand.
template<typename T>
auto print(T t) -> decltype(t.print()) {
return t.print();
}
int print(int t) {
return t;
}
std::string print(std::string t) {
return t;
}
// ... and so on, for each type you want to support ...
More advanced solution using SFINAE which uses T::print()
automatically if and only if it's there:
First, define a trait which can decide if your type has a function print()
. Basically, this trait inherits from either std::true_type
or std::false_type
, depending on the decision being made in some helper class (_test_print
). Then, use this type trait in an enable_if
compile-time decision which defines only one of the two cases and hides the other one (so this is not overloading).
// Type trait "has_print" which checks if T::print() is available:
struct _test_print {
template<class T> static auto test(T* p) -> decltype(p->print(), std::true_type());
template<class> static auto test(...) -> std::false_type;
};
template<class T> struct has_print : public decltype(_test_print::test<T>(0)) {};
// Definition of print(T) if T has T::print():
template<typename T>
auto print(T t) -> typename std::enable_if<has_print<T>::value, decltype(t.print())>::type {
return t.print();
}
// Definition of print(T) if T doesn't have T::print():
template<typename T>
auto print(T t) -> typename std::enable_if<!has_print<T>::value, T>::type {
return t;
}
Have a look at the live demo.