I believe that I have the perfect solution. It only requires the test function to be changed, so it only leaves SmartPtr and Variant, which is ideal. It adds an undefined template overload for validation, which has specializations for bool and nullptr, which are defined. This directly sends bool and nullptr to the required specialization, but causes errors in references to other raw types. I am so glad that it worked, because of course I come across this in many forms. I want you to be able to use explicit function parameters!
I got an idea from here: C ++ templates that accept only certain types
using namespace std; class Object { public: }; class Variant { public: Variant( bool b) : _b(b) { } private: bool _b; }; template<typename T> class SmartPtr { public: SmartPtr(std::nullptr_t null) { p_ = nullptr; } template<typename Y> SmartPtr(Y* p) { p_ = p; } private: T* p_; }; class Obj { public: void test(SmartPtr<Object> here ) { cout << "smartptr version!" << endl; } void test(Variant ) { cout << "variant version!" << endl; } template<typename T> void test(T t); template<> void test<bool>(bool b) { cout << "bool specialization" << endl; test(Variant(b)); } template<> void test<std::nullptr_t>(std::nullptr_t null) { cout << "nullptr specialization" << endl; test(SmartPtr<Object>(nullptr)); } }; int main(int argc, const char *argv[]) { Obj o; Obj c; Object object;
I already answered with something not perfect, so I leave this answer tactfully, as follows:
===============================================
I don't have the perfect solution here, and I don't know the limitations that you have on your code, so this may not be functional for you, but the following is reasonable. It prohibits the use of nullptr code at compile time and relies on the global constant null_smart, which will be used in all cases where the calling object simply does not show interest in passing the object.
#include <iostream> using namespace std; class Object { public: }; class Variant { public: Variant(bool b) : _b(b) { } private: Variant(std::nullptr_t) {}; private: bool _b; }; template<typename T> class SmartPtr { public: SmartPtr() { p_ = nullptr; } template<typename Y> SmartPtr(Y* p) { p_ = p; } private: T* p_; }; class Obj { public: void test(SmartPtr<Object> /*p*/) { cout << "smartptr version!" << endl; } void test(Variant /*v*/) { cout << "variant version!" << endl; } }; const SmartPtr<Object> null_smart; int main(int argc, const char *argv[]) { Obj o; o.test(null_smart); // calls SmartPtr version, without interest in passing object o.test(true); // calls Variant version o.test(false); // calls Variant version return 0; }
It is cleaner than the true / Variant (false) issue, but still a bit on the picky side.
source share