C ++强制转换为“叔类”

时间:2018-10-26 12:57:03

标签: c++ c++11 templates casting shared-ptr

我有一个Wrapper<T>模板类。

我有一个基类A。

我有一个派生类B:公共A。

我想要的是将Wrapper<B>存储在vector<Wrapper<A>>中。

从技术上讲,我知道这是不对的,因为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>类取得相同的结果?

这是非编译代码:

#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;
}

最好, 皮埃尔

1 个答案:

答案 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的转换构造函数为我们调整返回的指针。