c++ 将对象从擦除型对象铸造为具体类型

hgc7kmma  于 2023-05-30  发布在  其他
关注(0)|答案(1)|浏览(136)

我正在尝试使用类型擦除概念。基于对象类型,我想将其转换为具体类型。我试图这样做,如下图所示,但它没有工作。它打印一些数字而不是11。我做错了什么?

尝试

std::vector<Object> v;
v.emplace_back(Object(Obj1(11)));
v.emplace_back(Object(Obj2("test")));

Object o1 = v[0];
auto c1 = static_cast<Object::Concept*>(o1.object.get());
auto m1 = static_cast<Object::Model<Obj1>*>(c1);
std::cout << m1->object.i;

代码

enum class ObjType { ObjType1, ObjType2 };
struct Object
{
   template<typename T>
   Object(T&& obj): object(std::make_shared<Model<T>>(std::forward<T>(obj))) {}

    ObjType getType() const { return object->getType(); }

    struct Concept
    {
      virtual ~Concept() {}
      virtual ObjType getType() const = 0;
    };

    template<typename T>
    struct Model : Concept
    {
        Model(const T& t) : object(t) {}
        T object;
        ObjType getType() const override { return object.getType(); }
    };

    std::shared_ptr<Concept> object;
};

struct Obj1
{
   int i;
   Obj1(int i) : i(i) {}
   ObjType getType() const { return ObjType::ObjType1; }
};

struct Obj2
{
   std::string s;
   Obj2(std::string s) : s(s) {}
   ObjType getType() const { return ObjType::ObjType2; }
};
rjee0c15

rjee0c151#

将使用模板化构造函数,而不是要在中使用的默认复制构造函数

Object o1 = v[0];

这里使用的构造函数实际上是Object::Object<Object&>
为了避免这种情况,如果参数类型是Object(或任何对Object的引用),您可以简单地不使模板化构造函数适用:

struct Object
{
    template<typename T>
    requires !std::is_same_v<Object, std::remove_cvref_t<T>>
    Object(T&& obj)
        : object(std::make_shared<Model<T>>(std::forward<T>(obj)))
    {
    }
    ...
};

当然,如果您实际上想使用Object::Model<Object>,这可能是一个问题;如果您打算这样做,我建议在名称空间范围内添加一个make_object函数,而不是通过构造函数实现对象创建。
附加说明:很有可能为构造函数推导出的模板参数是Obj1&Obj1 const&(或Obj2的等价物),因此在选择Model类型时,您可能希望删除引用,并可能删除const

template<typename T>
requires !std::is_same_v<Object, std::remove_cvref_t<T>>
Object(T&& obj)
    : object(std::make_shared<Model<std::remove_reference_t<T>>>(std::forward<T>(obj)))
{
}

或者是

template<typename T>
requires !std::is_same_v<Object, std::remove_cvref_t<T>>
Object(T&& obj)
    : object(std::make_shared<Model<std::remove_cvref_t<T>>>(std::forward<T>(obj)))
{
}

**编辑:**对于C++14概念不能使用,std::remove_cvref_t也不可用,因此需要使用SFINAE和std::remove_const_t<std::remove_reference_t<...>>

...
template<typename T, std::enable_if_t<!std::is_same<std::remove_const_t<std::remove_reference_t<T>>, Object>::value, bool> = true>
Object(T&& obj)
    : object(std::make_shared<Model<std::remove_const_t<std::remove_reference_t<T>>>>(std::forward<T>(obj)))
{
}
...

相关问题