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::anyget_impl 中的 T*

当我们复制 RollbackElement 时,我们同时复制了 any(不转换为具体类型) get_impl。如果另一个回滚是不同的类型,我们依赖std::function的转换构造函数为我们调整返回的指针。