Конвертация политик работает только с конструктором - PullRequest
1 голос
/ 14 сентября 2010
#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 ]

2 голосов
/ 14 сентября 2010

Я не понимаю, почему 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 голос
/ 14 сентября 2010

Ваша operator EnforceNotNull<T>() функция не является const, поэтому компилятор не включает ее в набор возможных функций преобразования. Раскомментируйте EnforceNotNull скопируйте ctor или поставьте const на вышеуказанную функцию, и ваш код должен работать.

1 голос
/ 14 сентября 2010

Ваш код выглядит немного сложнее.Например, вам не нужно наследовать политику, если она не заботится о каком-либо состоянии, а это не ваш случай.Кроме того, наличие классов требует указания спецификаторов доступа, так что вам может быть лучше с структурами.

В любом случае, интеллектуальные указатели не могут быть скопированы, что является основным приемом.Вы можете только передать право собственности (движимое понятие).Так что ваш конструктор копирования немного некорректен.У вас все еще может быть это, если это явно ваше намерение, но убедитесь, что у вас есть какой-нибудь счетчик ссылок.

Вот ваш код, упрощенный и работающий:

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