Умный указатель для шаблона класса? - PullRequest
1 голос
/ 03 сентября 2011

Я подозреваю, что не могу сделать это напрямую, используя шаблон PIMPL. Можно ли иметь умный указатель на класс шаблона? Мне не удалось скомпилировать, повернув ручки в объявлении shared_ptr.

// ============Foo.h ============
// Forward declare the implementation
template <typename T> class FooImpl;

class Foo
{
  public:
    Foo getInstance(const string& fooType);
    ...
  private:
    shared_ptr< FooImpl<T> > m_impl;
};

// ============FooImpl.h ============
template <typename T>
class FooImpl
{
    ...
};

В Visual Studio 2008: «ошибка C2065:« T »: необъявленный идентификатор». Я получаю аналогичную ошибку при GCC. Если Я отменяю параметризацию FooImpl (так что FooTempl наследует от FooImpl), код скомпилируется.

Я подозреваю, что не могу параматизировать умный указатель, но могу ошибаться.

РЕДАКТИРОВАТЬ: секунда Ошибка Visual Studio более показательна: «ошибка C3203:« FooImpl »: шаблон неспециализированного класса не может использоваться в качестве аргумента шаблона для параметра шаблона« T », ожидается реальное типа "

Jeff

Ответы [ 5 ]

3 голосов
/ 03 сентября 2011

Я не совсем уверен, чего вы пытаетесь достичь, но помогает ли это?

Попробуйте 1:

// ============Foo.h ============
// Forward declare the implementation

template <typename T> class FooImpl;

template<class C>
class Foo
{
  public:
    Foo getInstance(const string& fooType);
    ...
  private:
    shared_ptr< FooImpl<C> > m_impl;
};

// ============FooImpl.h ============
template <typename T>
class FooImpl
{
    ...
};

Попробуйте 2:

// ============Foo.h ============
// Forward declare the implementation

class FooImplBase;

class Foo
{
  public:
    Foo getInstance(const string& fooType);
    ...
  private:
    shared_ptr< FooImplBase > m_impl;
};

// ============FooImpl.h ============
class FooImplBase {
  public:
    virtual void AnAPI();
    virtual int AnotherAPI();
};
template <typename T>
class FooImpl : public FooImplBase
{
    ...
};
1 голос
/ 03 сентября 2011

Код, который вы опубликовали, не может быть скомпилирован, так как T ничего не значит в контексте Foo.Компилятор ожидает здесь тип с именем T, которого там не существует ... Не совсем уверен, что вы пытаетесь достичь, но разве следующее не решит вашу проблему?

// ============Foo.h ============ 

class FooImplBase {
    virtual void WhateverFooImplIsSupposedToDo() = 0;
};

template <typename T> class FooImpl : public FooImplBase {
    T mInstance;
public:
    FooImpl(T const & pInstance) : mInstance(pInstance) {}
    virtual void WhateverFooImplIsSupposedToDo() 
    {
        // implementation which deals with instances of T
    }
}; 

class Foo 
{ 
  public: 
    Foo getInstance(const string& fooType) {
     // use m_impl->WhateverFooImplIsSupposedToDo...
    }    

    template < class T >
    Foo( T const & pInstance ) : m_impl(new FooImpl<T>(pInstance)) {}
  private: 
    shared_ptr< FooImplBase > m_impl; 
}; 
1 голос
/ 03 сентября 2011

Я не знаю заранее, у меня будет Бла, только Бла.

С языковой точки зрения Blah<T> не имеет смысла, поскольку T не существует. В зависимости от того, что именно вы пытаетесь сделать, вы можете

сделать Foo шаблоном, чтобы вы могли объявить параметр шаблона T:

template<typename T>
class Foo
{
  public:
    Foo getInstance(const string& fooType);
    ...
  private:
    shared_ptr< FooImpl<T> > m_impl;
};

, который «исправляет» выбор T при объявлении переменной типа Foo<T>;

или make FooImpl явно производные от общей базы:

class FooBase {
    // need to define the interface here
};

// this is a class definition whereas previously you only needed a declaration
template<typename T>
class FooImpl: public FooBase {
    // definition here
};

class Foo
{
  public:
    Foo getInstance(const string& fooType);

    // we needed the definition of FooImpl for this member
    // in addition this member is quite obviously a template
    template<typename T>
    void
    set(FooImpl<T> const& foo)
    {
        m_impl.reset(new FooImpl<T>(foo));
    }

    // not a member template!
    void
    use()
    {
        // any use of m_impl will be through the FooBase interface
    }

  private:
    shared_ptr<FooBase> m_impl;
};

, где для данного экземпляра Foo любой тип FooImpl<T> может быть установлен динамически, а затем использован через интерфейс FooBase. Это своего рода стирание типа , как его называют в мире C ++.

1 голос
/ 03 сентября 2011

Вы делаете это правильно, просто убедитесь, что T определено.Это скомпилировано для меня в MSVC ++ 2010:

#include <memory>

using namespace std;

template<class T>
class Blah {
public:
    Blah() { }
};

class Foo {
public:
    shared_ptr<Blah<int>> ptr;

    Foo() : ptr(new Blah<int>()) { }
};

Если вы используете более старый компилятор, который еще не включил эту функцию в C ++ 11, измените

shared_ptr<Blah<int>> ptr;

на

shared_ptr<Blah<int> > ptr;

Таким образом, компилятор не считает >> правильным сдвигом.В C ++ 11 такой проблемы нет.

0 голосов
/ 23 марта 2018

Мы можем использовать шаблоны для написания универсального класса интеллектуальных указателей. Следующий код C ++ демонстрирует то же самое. Нам не нужно вызывать delete 'ptr', когда объект 'ptr' выходит из области видимости, деструктор для него автоматически.

#include<iostream>
using namespace std;

// A generic smart pointer class
template <class T>
class SmartPtr
{
   T *ptr;  // Actual pointer
public:
   // Constructor
   explicit SmartPtr(T *p = NULL) { ptr = p; }

   // Destructor
   ~SmartPtr() {
    cout <<"Destructor called" << endl;  
    delete(ptr);
   }

   // Overloading dereferncing operator
   T & operator * () {  return *ptr; }

   // Overloding arrow operator so that members of T can be accessed
   // like a pointer (useful if T represents a class or struct or 
   // union type)
   T * operator -> () { return ptr; }
};

int main()
{
    SmartPtr<int> ptr(new int()); // Here we can create any data type pointer just like 'int'
    *ptr = 20;
    cout << *ptr;
    return 0;
}

выход:

20

Деструктор называется

...