模板化类的Pimpl
pimpl for a templated class
本文关键字:Pimpl 更新时间:2023-10-16
我想使用pimpl习惯用法来避免我的库的用户需要我们的外部依赖(如boost等),但是当我的类被模板化时,这似乎是不可能的,因为方法必须在头文件中。有什么我可以代替的吗?
如果类是模板化的,你的用户本质上需要编译它(在最广泛使用的c++实现中确实如此),因此他们需要你的外部依赖项。
最简单的解决方案是将类的大部分实现放在非模板基类(或某些类的封装成员对象)中。解决模块隐藏问题。
然后编写模板派生(或封闭)类,为其添加类型安全。
例如,假设您有一个模板,它提供了在首次访问时进行分配的惊人能力(省略了必要的复制构造函数、赋值函数、析构函数):template <class T>
class MyContainer
{
T *instance_;
public:
MyContainer() : instance_(0) {}
T &access()
{
if (instance_ == 0)
instance_ = new T();
return *instance_;
}
};
如果你想把"逻辑"分离成一个非模板基类,你必须以非模板的方式参数化行为,也就是说,使用虚函数:
class MyBase
{
void *instance_;
virtual void *allocate() = 0;
public:
MyBase() : instance_(0) {}
void *access()
{
if (instance_ == 0)
instance_ = allocate();
return instance_;
}
};
然后你可以在外层添加类型感知:
template <class T>
class MyContainer : MyBase
{
virtual void *allocate()
{ return new T(); }
public:
T &access()
{ return *(reinterpret_cast<T *>(MyBase::access())); }
};
。使用虚函数允许模板"填充"与类型相关的操作。显然,只有当您有一些值得隐藏的业务逻辑时,这种模式才真正有意义。
您可以在源文件中显式地实例化模板,但这只有在您知道模板类型的情况下才有可能。否则,不要在模板中使用pimpl习语。
像这样:
header.hpp:
#ifndef HEADER_HPP
#define HEADER_HPP
template< typename T >
class A
{
// constructor+methods + pimpl
};
#endif
source.cpp:
#include "header.hpp"
// implementation
// explicitly instantiate for types that will be used
template class A< int >;
template class A< float >;
// etc...
一般有两种解决方案:
-
虽然接口依赖于某些类型
T
,但它遵循更弱类型的实现(例如直接使用void*
指针或通过类型擦除),或者 -
你只支持一种特定的、相当有限的类型
第二个解决方案适用于例如char
/wchar_t
依赖性物质。
第一种解决方案在c++模板的早期是相当普遍的,因为那时编译器不善于识别生成的机器代码中的共性,并且会引入所谓的"代码膨胀"。今天,让任何尝试过模板化解决方案的新手感到惊讶的是,模板化解决方案通常比依赖于运行时多态性的解决方案占用更小的机器代码。当然,YMMV。
干杯,hth。
相关文章:
- Qt中的实现指针(PIMPL)
- 为什么在PIMPL中无法访问实现类的常量函数?
- 使用 PIMPL 惯用法,实现是否应始终是类的私有成员?
- C++详细介绍命名空间 vs 匿名 vs 私有方法到类 vs. pimpl vs. 朋友类
- pImpl、范围和隐藏数据成员
- 实施 pimpl 友好型unique_ptr
- 何时在C 中使用嵌套类上的PIMPL模式,反之亦然
- pimpl和定义类别的.cpp文件之间的区别
- C PIMPL成语,类模板和void模板参数
- PIMPL类的设置应该是const成员函数
- D 指针/pimpl 模式基类指针访问派生类成员
- 使用可变参数模板函数在类周围实现基于 pImpl 的包装器
- 将 PIMPL 习惯用法与成员函数模板一起使用(无需预先了解所有可能的数据类型)
- 像这样的PIMPL实现是否有任何简单的语法
- C++17 pimpl 习语上下文中的自定义迭代器
- 尝试实施 PIMPL idom 时如何避免"redefinition; different basic types"
- pimpl 在 C++ 应用程序/库中的什么位置使用?任何例子
- memcpy在尝试"快速"pimpl时未优化
- Pimpl with unique_ptr : 为什么我必须将接口构造函数的定义移动到".cpp"?
- 其他原因或目的是使用Pimpl Idoim