C++ 转换为 "uncle class"
C++ Cast to "uncle class"
我有一个 Wrapper<T>
模板 class。
我有一个基地 class A.
我有一个派生的 class B : public A.
我想要的是在vector<Wrapper<A>>
中存储一个Wrapper<B>
。
我知道这在技术上是不对的,因为 Wrapper<B>
不是 Wrapper<A>
的直接子 class
See inheritance diagram
但不知何故,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>
class 实现相同的结果?
这是非编译代码:
#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;
}
最好的,
皮埃尔
A 和 B 的共享指针是不相关的类型。
shared ptr 的作用是提供一个转换构造函数。只要可以转换指针类型,它就接受原始指针和共享指针。
Shared ptr type擦除如何做最后的销毁,并存储指针,所以这个真的不难。
具体如何工作将取决于数据的存储方式和 Wrapper 的功能。
但是:
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);
}
};
这里不是存储 actual T
,而是存储围绕 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
到 get_impl
中的 T*
。
当我们复制 RollbackElement
时,我们同时复制了 any(不转换为具体类型)和 get_impl
。如果另一个回滚是不同的类型,我们依赖std::function
的转换构造函数为我们调整返回的指针。
我有一个 Wrapper<T>
模板 class。
我有一个基地 class A.
我有一个派生的 class B : public A.
我想要的是在vector<Wrapper<A>>
中存储一个Wrapper<B>
。
我知道这在技术上是不对的,因为 Wrapper<B>
不是 Wrapper<A>
See inheritance diagram
但不知何故,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>
class 实现相同的结果?
这是非编译代码:
#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;
}
最好的, 皮埃尔
A 和 B 的共享指针是不相关的类型。
shared ptr 的作用是提供一个转换构造函数。只要可以转换指针类型,它就接受原始指针和共享指针。
Shared ptr type擦除如何做最后的销毁,并存储指针,所以这个真的不难。
具体如何工作将取决于数据的存储方式和 Wrapper 的功能。
但是:
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);
}
};
这里不是存储 actual T
,而是存储围绕 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
到 get_impl
中的 T*
。
当我们复制 RollbackElement
时,我们同时复制了 any(不转换为具体类型)和 get_impl
。如果另一个回滚是不同的类型,我们依赖std::function
的转换构造函数为我们调整返回的指针。