类型擦除技术
|
(使用类型擦除,我的意思是隐藏有关某个类的一些或所有类型信息,有点像Boost.Any。)
我想掌握类型擦除技术,同时也分享我所知道的那些技术。我的希望是找到一些在他/她最黑暗的时刻想到的疯狂技术。 :)
我知道,第一个也是最常见的方法是虚函数。只需在基于接口的类层次结构中隐藏类的实现即可。许多Boost库都执行此操作,例如Boost.Any执行此操作以隐藏您的类型,Boost.Shared_ptr执行此操作以隐藏(取消)分配机制。
然后是带有指向模板化函数的函数指针的选项,同时将实际对象保持在
void*
指针中,就像Boost.Function确实隐藏了函子的真实类型。示例实现可以在问题的末尾找到。
因此,对于我的实际问题:
您还知道其他哪些类型的擦除技术?请为他们提供示例代码,用例,您的使用经验以及可能的链接,以供进一步阅读。
编辑
(由于我不确定是否可以将此问题添加为答案,或者只是编辑问题,因此我会比较安全。)
隐藏人的实际类型的另一种不错的技术是不使用虚函数或“ 0”摆弄,这是GMan在这里使用的一种技术,与我对它到底是如何工作的问题有关。
示例代码:
#include <iostream>
#include <string>
// NOTE: The class name indicates the underlying type erasure technique
// this behaves like the Boost.Any type w.r.t. implementation details
class Any_Virtual{
struct holder_base{
virtual ~holder_base(){}
virtual holder_base* clone() const = 0;
};
template<class T>
struct holder : holder_base{
holder()
: held_()
{}
holder(T const& t)
: held_(t)
{}
virtual ~holder(){
}
virtual holder_base* clone() const {
return new holder<T>(*this);
}
T held_;
};
public:
Any_Virtual()
: storage_(0)
{}
Any_Virtual(Any_Virtual const& other)
: storage_(other.storage_->clone())
{}
template<class T>
Any_Virtual(T const& t)
: storage_(new holder<T>(t))
{}
~Any_Virtual(){
Clear();
}
Any_Virtual& operator=(Any_Virtual const& other){
Clear();
storage_ = other.storage_->clone();
return *this;
}
template<class T>
Any_Virtual& operator=(T const& t){
Clear();
storage_ = new holder<T>(t);
return *this;
}
void Clear(){
if(storage_)
delete storage_;
}
template<class T>
T& As(){
return static_cast<holder<T>*>(storage_)->held_;
}
private:
holder_base* storage_;
};
// the following demonstrates the use of void pointers
// and function pointers to templated operate functions
// to safely hide the type
enum Operation{
CopyTag,
DeleteTag
};
template<class T>
void Operate(void*const& in, void*& out, Operation op){
switch(op){
case CopyTag:
out = new T(*static_cast<T*>(in));
return;
case DeleteTag:
delete static_cast<T*>(out);
}
}
class Any_VoidPtr{
public:
Any_VoidPtr()
: object_(0)
, operate_(0)
{}
Any_VoidPtr(Any_VoidPtr const& other)
: object_(0)
, operate_(other.operate_)
{
if(other.object_)
operate_(other.object_, object_, CopyTag);
}
template<class T>
Any_VoidPtr(T const& t)
: object_(new T(t))
, operate_(&Operate<T>)
{}
~Any_VoidPtr(){
Clear();
}
Any_VoidPtr& operator=(Any_VoidPtr const& other){
Clear();
operate_ = other.operate_;
operate_(other.object_, object_, CopyTag);
return *this;
}
template<class T>
Any_VoidPtr& operator=(T const& t){
Clear();
object_ = new T(t);
operate_ = &Operate<T>;
return *this;
}
void Clear(){
if(object_)
operate_(0,object_,DeleteTag);
object_ = 0;
}
template<class T>
T& As(){
return *static_cast<T*>(object_);
}
private:
typedef void (*OperateFunc)(void*const&,void*&,Operation);
void* object_;
OperateFunc operate_;
};
int main(){
Any_Virtual a = 6;
std::cout << a.As<int>() << std::endl;
a = std::string(\"oh hi!\");
std::cout << a.As<std::string>() << std::endl;
Any_Virtual av2 = a;
Any_VoidPtr a2 = 42;
std::cout << a2.As<int>() << std::endl;
Any_VoidPtr a3 = a.As<std::string>();
a2 = a3;
a2.As<std::string>() += \" - again!\";
std::cout << \"a2: \" << a2.As<std::string>() << std::endl;
std::cout << \"a3: \" << a3.As<std::string>() << std::endl;
a3 = a;
a3.As<Any_Virtual>().As<std::string>() += \" - and yet again!!\";
std::cout << \"a: \" << a.As<std::string>() << std::endl;
std::cout << \"a3->a: \" << a3.As<Any_Virtual>().As<std::string>() << std::endl;
std::cin.get();
}
没有找到相关结果
已邀请:
6 个回复
抚驰
(用于数据)来完成的。 “不同”方法的不同之处仅在于它们添加语义糖的方式不同。虚拟功能,例如,对于
iow:函数指针。 也就是说,我特别喜欢一种技术:5英镑,这仅仅是因为它使那些不知道可以执行此操作的人大吃一惊:您可以将数据存储在5英镑中,并且最后仍然调用了正确的析构函数,因为
构造函数是一个函数模板,并且默认情况下将使用传递的实际对象的类型来创建删除器:
当然,这只是通常的
/功能指针类型的擦除,但打包起来非常方便。
靛新比比催
漂截嘘
)使用\“ raw storage \”:
。 在C ++ 0x中,您需要
。 您可以在其中存储任何想要的东西,只要它足够小并且可以正确处理对齐方式即可。
凰葱崎济邯
,这是沿着
的容器。当您经常在各种不同的指针类型上使用ѭ17时,编译器会为每种指针类型生成不同的代码。 通过为by0ѭ指针定义Vector的特殊化,然后将此特殊化用作所有其他类型ѭ20using的
的通用基本实现,可以避免此代码膨胀:
如您所见,我们有一个强类型化的容器,但是
,
,
,...将共享相同的(C ++和二进制)代码用于实现,其指针类型被删除在
之后。
摊揉售
痴浪墨
。 例如,将类型存储在函数指针中,对其进行强制转换并将其存储在仅一种类型的函子中: