我有一个Wrapper<T>
模板类。
我有一个基类A。
我有一个派生类B:公共A。
我想要的是将Wrapper<B>
存储在vector<Wrapper<A>>
中。
从技术上讲,我知道这是不对的,因为Wrapper<B>
不是Wrapper<A>
的直接子类
但是以某种方式,STL允许shared_ptr:
#include <memory>
#include <vector>
#include <iostream>
struct A
{
A() {}
virtual ~A() {}
virtual void print() { std::cout << "A" << std::endl; }
};
struct B : public A
{
B() {}
virtual ~B() {}
virtual void print() { std::cout << "B" << std::endl; }
};
int main()
{
std::vector<std::shared_ptr<A>> v;
v.push_back(std::make_shared<A>());
v.push_back(std::make_shared<B>());
for (auto &e : v)
e->print();
return 0;
}
如何为我的Wrapper<T>
类取得相同的结果?
这是非编译代码:
#include <vector>
#include <iostream>
template <class T>
struct W
{
};
struct A
{
A() {}
virtual void print() { std::cout << "A" << std::endl; }
};
struct B : public A
{
B() {}
virtual void print() { std::cout << "B" << std::endl; }
};
int main()
{
std::vector<W<A>> v;
v.push_back(W<A>());
v.push_back(W<B>());
for (auto &e : v)
e->print();
return 0;
}
最好, 皮埃尔
答案 0 :(得分:3)
与A和B共享的ptr是不相关的类型。
共享ptr所做的是提供一个转换构造函数。只要可以转换指针类型,它就可以同时接受raw-pointer-to和shared-ptr-to。
共享的ptr类型删除了如何进行最终销毁,并存储了指针,因此这确实不难。
这究竟如何工作将取决于如何存储数据以及包装器的作用。
但是:
template<class T>
struct Wrapper {
template<class U>
Wrapper(Wrapper<U>);
};
基本上就是它。也许有些SFINAE可以得到更早的错误。
...
实际上您已在评论中添加了详细信息,因此您具有:
template<class T>
struct RollbackElement : public T
为Wrapper
。答案是,不,你不能那样做。
您可以这样做:
template<class T>
struct RollbackElement : public std::any {
operator T&() {
return std::any_cast<T&>(*this);
}
};
您可以在T
周围存储类型擦除包装器,而不是存储 actual T
。
template<class T>
struct RollbackElement : private std::any {
operator T&() {
return *get();
}
operator T const&() const {
return *get();
}
RollbackElement( T in ):
std::any(std::move(in)),
get_impl([](std::any& x)->T*{return std::any_cast<T*>(&x);})
{}
RollbackElement():RollbackElement({}) {}
template<class U>
RollbackElement( RollbackElement<U> const& o ):
std::any( static_cast<std::any const&>(o) ),
get_impl(o.get_impl)
{}
// note: due to quirks in `std::any`, a move ctor isn't safe
T* operator->() { return get(); }
T const* operator->() const { return get(); }
T* get() { return get_impl(*this); }
T const* get() const { return get_impl(const_cast<std::any&>(*this)); }
private:
std::function<T*(std::any&)> get_impl = {};
};
加上您想要的增强效果
这里的窍门是,您的存储std::any
可以存储任何内容。
我们在std::any
中存储如何从T*
到get_impl
。
当我们复制RollbackElement
时,我们同时复制了any(没有强制转换为具体类型)和 get_impl
。如果另一个Rollback是 different 类型,则我们依靠std::function
的转换构造函数为我们调整返回的指针。