众所周知,如果我们从头开始设计类型系统,那么我们可以使用类型擦除技术来实现多态。但是,我们应该如何将类型擦除技术应用于现有类型,如下例?
struct A
{
int f()
{
return 1;
}
};
struct B
{
int f()
{
return 2;
}
};
template<class TypeForOtherUse> // Don't put A or B here
struct C
{
C(A a)
: obj_of_A_or_B(a)
{}
C(B b)
: obj_of_A_or_B(b)
{}
int g()
{
return obj_of_A_or_B.f();
}
/* ??? What should be put here ??? */ obj_of_A_or_B;
};
答案 0 :(得分:1)
boost
有一个完整的类型擦除库,可让您选择要删除的内容。
但是,如上所述的简单案例可以如下进行:
// The interface detailing what we support. Move is always supported.
// only need clone if we want to copy:
struct IImpl {
virtual std::unique_ptr<IImpl> clone() const = 0;
virtual int f() = 0;
virtual ~IImpl() {}
};
// The pImpl<T> class writes custom code to type erase a type T.
// you can specialize it for extreme cases: ie, suppose for some type X
// you want f() to invoke g() -- then you can specialize Impl to do that.
// (that is a bit of a toy example, and a bad one, but imagine std::function
// specialized for method pointers such that `this` is turned into the first
// argument)
template<class T>
struct Impl:IImpl {
T t;
virtual std::unique_ptr<IImpl> clone() const override {
return std::unique_ptr<IImpl>( new Impl(t) );
}
virtual int f() const override {
return t.f();
}
virtual ~Impl() {}
template<typename...Us>
explicit Impl( Us&&... us ): t(std::forward<Us>(us)...) {}
// copy is handled by clone. move is handled by unique_ptr:
Impl( Impl const& ) = delete;
Impl& operator=( Impl const& ) = delete;
};
// the value-semantics class that type-erases:
struct TypeErased {
std::unique_ptr<IImpl> pImpl; // where the work is mostly done
int f() { return pImpl->f(); } // forward to where the work is mostly done
template<typename T, typename... Us> // pass T explicitly, allow construction from other types
void emplace( Us&&... us ) { pImpl.reset( new Impl<T>(std::forward<Us>(us)...) ); }
template<typename T> // like std::function, sucks in similar ways
explicit TypeErased( T&& t ): pImpl( new Impl<typename std::decay<T>::type>(std::forward<T>(t)) {};
TypeErased(TypeErased&&) = default;
TypeErased(TypeErased const&o): pImpl( o.pImpl?o.pImpl->clone():nullptr ) {}
TypeErased(TypeErased const&&o):TypeErased(o) {} // delegate to const&, no need to cast here
TypeErased(TypeErased&o):TypeErased( const_cast<TypeErased const&>(o) {} // delegate to const&
TypeErased& operator=(TypeErased&&) = default; // moving the unique_ptr does the right thing
TypeErased& operator=(TypeErased const&o) { // copy-swap idiom
TypeErased tmp(o);
this->swap(tmp);
return *this;
}
void swap( TypeErased& o ) {
std::swap( pImpl, o.pImpl );
}
};
// You can make this a template on other types, but I'll omit it, as it just fuzzies things up:
struct C {
C(A a): erased(a) {}
C(B b): erased(b) {}
int g() {
return erased.f();
}
TypeErased erased;
};
没有编译,但我再次阅读它并摆脱了大部分拼写错误。