策略转换仅适用于构造函数

时间:2010-09-14 18:55:44

标签: c++ policies

#include "stdafx.h"
#include <exception>

template<class T>
class NoCheck;

template<class T>
class EnforceNotNull
{
public:
    //EnforceNotNull(const NoCheck<T>&){}//<<-----If this is uncommented it works
    static void Check(T* p)
    {
        class NullPtrException : public std::exception
        {
        };

        if (!p)
        {
            throw NullPtrException();
        }
    }
};

template<class T>
class NoCheck
{
public:
    NoCheck(){}
    NoCheck(const NoCheck&){}
    NoCheck(const EnforceNotNull<T>&){}
    operator EnforceNotNull<T>() {return EnforceNotNull<T>();}//<<-----This seams to not do its job
    static void Check(T* p)
    {/*Empty body*/}
};


template<class T, template<class> class CheckingPolicy>
class SmartPtr : public CheckingPolicy<T>
{
public:
    SmartPtr(T* p)
    {
        Check(p);
    }

    template<class T1, template <class> class CheckingPolicy1>
    SmartPtr(const SmartPtr<T1,CheckingPolicy1>& pattern):pointee_(pattern.pointee_),
        CheckingPolicy<T>(pattern)
    {
    }
    T* pointee_;
private:

};

int _tmain(int argc, _TCHAR* argv[])
{

    SmartPtr<int,NoCheck> p1(nullptr);
    SmartPtr<int,EnforceNotNull> p = p1;//I'm trying here to convert NoCheck to    

   // EnforceNotNull but it works for me only if I use ctor, if I use conversion optor   
//(from  


  //  NoCheck to EnforceNotNull) it doesn't work why?
    return 0;
}

3 个答案:

答案 0 :(得分:2)

我不明白为什么必须从检查策略继承SmartPtr。我也不明白为什么政策必须是模板本身。

为什么不简单:

#include <cstdlib>
#include <exception>

class EnforceNotNull
{
public:
    template <class T>
    static void Check(T* p)
    {
        class NullPtrException : public std::exception
        {
        };

        if (!p)
        {
            throw NullPtrException();
        }
    }
};


class NoCheck
{
public:
    template<class T>
    static void Check(T* p)
    {/*Empty body*/}
};


template<class T, class CheckingPolicy>
class SmartPtr
{
public:
    SmartPtr(T* p)
    {
        CheckingPolicy::Check(p);
    }

    template<class T1, class CheckingPolicy1>
    SmartPtr(const SmartPtr<T1,CheckingPolicy1>& pattern):pointee_(pattern.pointee_)
    {
        CheckingPolicy::Check(pointee_);  //pattern's pointee_ may not pass our check
    }
    T* pointee_;
private:

};

int main()
{

    SmartPtr<int,NoCheck> p1(NULL);
    SmartPtr<int,EnforceNotNull> p = p1;
    return 0;
}

答案 1 :(得分:1)

您的代码看起来有点过于复杂。例如,除非它关注某个状态,否则您不必继承策略,这不是您的情况。另外,拥有类需要使用访问说明符,因此使用结构可能会更好。

无论如何,智能指针无法复制,这是主要技巧。您只能转让所有权(可移动的概念)。所以你的拷贝构造函数有点不正确。如果这显然是你的意图,你可能仍然拥有它,但请确保你有一些参考计数器。

以下是您的代码,简化并正常工作:

#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");
    }
}

以下是使用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");
    }
}

答案 2 :(得分:1)

您的operator EnforceNotNull<T>()函数不是const,因此编译器不会将其包含在可能的转换函数集中。取消注释EnforceNotNull复制ctor或将const放在上面的函数上,您的代码应该可以正常工作。