Your code looks a little bit overcomplicated. For example, you don't have to inherit a policy unless it cares some state, which is not your case. Plus, having classes requires putting access specifiers, so you might be better off with structs.
Anyways, smart pointers cannot be copied, that is the main trick. You can only transfer ownership (movable concept). So your copy constructor is a bit incorrect. You may still have it if that is clearly your intent, but make sure you have some reference counter whatsoever.
Here is your code, simplified and working:
#include <cstdio>
#include <cstddef>
#include <exception>
class NullPtrException : public std::exception
{
};
template <typename T>
struct EnforceNotNull
{
static void Check(T *p)
{
if (p == NULL)
{
throw NullPtrException();
}
}
};
template <typename T>
struct NoCheck
{
static void Check(T *)
{
}
};
template <typename T, template <typename> class CheckingPolicy>
class SmartPtr
{
T* pointee_;
public:
SmartPtr (T* p) :
pointee_ (p)
{
CheckingPolicy<T>::Check (pointee_);
}
template <typename T1, template <typename> class CheckingPolicy1>
SmartPtr (SmartPtr<T1, CheckingPolicy1> & pattern) :
pointee_ (pattern.get ())
{
CheckingPolicy<T>::Check (pointee_);
pattern.release ();
}
~SmartPtr ()
{
delete pointee_;
pointee_ = NULL;
}
T *get ()
{
return pointee_;
}
T *release ()
{
T *result = pointee_;
pointee_ = NULL;
return result;
}
};
int main()
{
try
{
printf ("Creating NULL pointer...\n");
SmartPtr<int, NoCheck> p1 (NULL);
printf ("Changing policy... \n");
SmartPtr<int, EnforceNotNull> p = p1;
printf ("This doesn't work :-(\n");
}
catch (const NullPtrException &)
{
printf ("GOTCHA!!!\n");
}
}
Here is how you enforce conversions using MPL:
#include <cstdio>
#include <cstddef>
#include <exception>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/or.hpp>
class NullPtrException : public std::exception {};
struct EnforceNotNull
{
template <typename T>
static void Check(T *p)
{
if (p == NULL)
throw NullPtrException();
}
};
struct NoCheck
{
template <typename T>
static void Check(T *) {}
};
template <typename T, typename CheckingPolicy>
class SmartPtr
{
T* p_;
public:
SmartPtr (T* p) :
p_ (p)
{
CheckingPolicy::Check (p_);
}
template <typename T1, typename PolicyT>
SmartPtr (SmartPtr<T1, PolicyT> & ptr,
// Enable moving from no checking pointer to any pointer
// or checking pointer to checking pointer.
// This makes it impossible to transfer checking to non-checking pointer.
typename boost::enable_if< boost::mpl::or_ <
boost::is_same<PolicyT, NoCheck>,
boost::is_same<PolicyT, CheckingPolicy> > >::type *dummy = NULL) :
p_ (ptr.get ())
{
CheckingPolicy::Check (p_);
ptr.release ();
}
~SmartPtr ()
{
delete p_;
p_ = NULL;
}
T *get () const
{
return p_;
}
T *release ()
{
T *result = p_;
p_ = NULL;
return result;
}
};
int main()
{
try
{
SmartPtr<int, NoCheck> p1 (NULL);
SmartPtr<int, EnforceNotNull> p2 = p1;
// SmartPtr<int, NoCheck> p3 = p2; // This will not compile.
}
catch (const NullPtrException &)
{
printf ("GOTCHA!!!\n");
}
}