模板类的智能指针?
Posted
技术标签:
【中文标题】模板类的智能指针?【英文标题】:Smart Pointer for a template class? 【发布时间】:2011-09-03 02:34:10 【问题描述】:我怀疑我不能直接使用 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),代码将编译。
我怀疑我无法参数化智能指针,但我可能错了。
编辑:second Visual Studio 错误更能说明问题:“错误 C3203: 'FooImpl' : unspecialized class template can't be used as a template argument for template parameter 'T', expected a实型”
杰夫
【问题讨论】:
T
在shared_ptr<FooImpl<T>> m_impl;
声明中是什么类型? Foo
应该是接受T
的模板吗?
@silico: T 将是 Crypto++ 对象,例如 MD5、SHA1、SHA256 等哈希值。
您遇到什么错误? 总是发布编译器错误。
【参考方案1】:
我不完全确定您要完成什么,但这有帮助吗?
尝试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
...
;
【讨论】:
最后,我无法使用带有模板参数的智能指针,我不得不切换到 3 个类(该死的几乎与上面的数字 2 完全一样)。【参考方案2】:您发布的代码无法编译,因为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;
;
【讨论】:
从概念上讲,这与我想要的相似。但是,我不希望用户必须声明Foo<int> f
。我不得不删除参数化的智能指针,并使用 3 个类。
嗯,使用这种类型排列,您不必定义Foo<int>
。您实际上不能,因为Foo
不是类模板...您的用户在调用站点编写Foo tTmp = 5;
之类的表达式或编写void TakeFoo(Foo const & pF)
之类的函数或使用TakeFoo(123.5);
之类的表达式。这是否有意义取决于您想要实现的目标。【参考方案3】:
您做对了,只需确保已定义 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 没有这个问题。
【讨论】:
好的。让我回到它(我一直在使用 FooImplFoo
设为模板即可。
我想这样做,但这妨碍了它在客户端代码中的使用。我希望用户能够做到Foo f = Foo::getInstance(...)
。
@noloader 如果Foo
是模板,则Foo f = ...
无效。对于某些T
,它必须为Foo<T> f = ...
。【参考方案4】:
我事先不知道我会有一个 Blah,只有一个 Blah。
从语言的角度来看,Blah<T>
没有意义,因为T
不存在。根据您的具体目标,您可以
把Foo
也做成一个模板,这样你就可以声明一个模板参数T
:
template<typename T>
class Foo
public:
Foo getInstance(const string& fooType);
...
private:
shared_ptr< FooImpl<T> > m_impl;
;
当您声明Foo<T>
类型的变量时,它“修复”了T
的选择;
或使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
接口使用。这是一种type erasure,因为它在 C++ 世界中被称为。
【讨论】:
【参考方案5】:我们可以使用模板来编写一个通用的智能指针类。以下 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
调用析构函数
【讨论】:
以上是关于模板类的智能指针?的主要内容,如果未能解决你的问题,请参考以下文章
第十六章 String类和标准模板库(1. string类智能指针)