Of course, there are many ways to do this. The first way that comes to my mind is simply overloading the functions. Since you do not have a parameter for overloading, you will have to create it. I like pointers that act effectively as a way to pass types to functions.
class Foo { //regular overload template<typename T> T bar(T*) { //takes a pointer with an NULL value cout << "Called with return type: " << typeid(T).name() << endl; T t = //... (some implementation here) return t; } //shared_ptr overload - NOTE THAT T IS THE POINTEE, NOT THE SHARED_PTR template<typename T> std::shared_ptr<T> bar(std::shared_ptr<T>*) { //takes a pointer with an null value cout << "Called with return type: " << typeid(T).name() << endl; std::shared_ptr<T> t = //... (some implementation here) return t; } public: template <typename T> T bar() { T* overloadable_pointer = 0; return bar(overloadable_pointer); } };
I have never heard anyone else use pointers to pass types, so if you decide to do this, comment it out completely to be safe. This is a weird code.
It may be more intuitive to simply use an auxiliary structure to specialize templates, which most people will do. Unfortunately, if you need access to Foo members (which you presumably do), using template specialization will require that you pass all of these members to a function or to a friend template helpers. Alternatively, you can pass the type_traits specialization to another member, but that ends with just the complicated version of the pointer trick above. Many people find this more normal and less confusing, so here's what:
template<typename T> struct Foo_tag {}; class Foo { //regular overload template<typename T> T bar(Foo_tag<T>) { } //shared_ptr overload - NOTE THAT T IS THE POINTEE, NOT THE SHARED_PTR template<typename T> std::shared_ptr<T> bar(Foo_tag<std::shared_ptr<T>>) { } public: template <typename T> T bar() { return bar(Foo_tag<T>{}); } }
source share