gpt4 book ai didi

c++ - 有没有办法在 C++ 中同时为多个模板分配一个类型?

转载 作者:行者123 更新时间:2023-11-30 03:21:43 25 4
gpt4 key购买 nike

这道题是基于下面的示例代码,它的灵感来自 Sean Parent's talk .下面代码的目标是提供一个类似于 boost::any 的对象包装器.我写这段代码是为了让自己了解类型删除。因此,此代码没有实际用途(考虑到已经有 boost::any)。

class ObjWrap {
public:
template <typename T>
ObjWrap(T O) : Self(new Obj<T>(std::move(O))) {}

template <typename T>
friend typename T * getObjPtr(ObjWrap O) {
return static_cast<T*>(O.Self->getObjPtr_());
}
private:
struct Concept {
virtual ~Concept() = 0;
virtual void* getObjPtr_() = 0;
};
template <typename T>
struct Obj : Concept {
Obj(T O) : Data(std::move(O)) {}
void* getObjPtr_() { return static_cast<void*>(&Data); }

T Data;
};

std::unique_ptr<Concept> Self;
};

在我真正提出问题之前,让我们从以下几个方面检查代码:

  1. Concept::getObjPtr_返回 void*因为 a) Concept否则不能是模板 unique_ptr<Concept> Self不会工作; b) void*是我知道如何返回的唯一方法 Obj::Data在 C++ 中以类型不可知的方式。如有不妥请指正...

  2. T * getObjPtr(ObjWrap O)是一个需要与 ObjWrap 分开实例化的模板构造函数。

  3. 使用ObjWrap基本上包括:a)制作一个新的ObjWrap在现有对象上; b) 检索给定 ObjWrap 的基础对象.例如:

    ObjWrap a(1);
    ObjWrap b(std::string("b"));
    int* p_a = getObjPtr<int>(a);
    std::string* p_b = getObjPtr<std::string>(b);

这有效,但很明显 getObjPtr<int>(b)不按预期工作。

那么,我的问题是:

有没有办法修复上面的代码,这样我们就可以简单地使用int* p_a = getObjPtr(a)std::string* p_b = getObjPtr(b)或者更好auto p_a = getObjPtr(a)auto p_b = getObjPtr(b) ?换句话说,C++ 中有没有办法同时实例化两个模板(如果是这样,我们可以实例化 ObjWrap 构造函数和 T* getObjPtr(ObjWrap)ObjWrap 对象的编译时,例如 ObjWrap a(1) ) ?

编辑 1:

使 ObjWrap 成为模板类没有帮助,因为它违背了类型删除的目的。

template <typename T>
class ObjWrap {
/* ... */
};

ObjWrap<int> a(1); // this is no good for type erasure.

编辑 2:

我正在阅读代码并意识到可以对其进行修改以更好地反射(reflect)这个想法。所以,也请看下面的代码:

class ObjWrap {
public:
template <typename T>
ObjWrap(T O) : Self(new Obj<T>(std::move(O))) {}

template <typename T>
T * getObjPtr() {
return static_cast<T*>(Self->getObjPtr_());
}
private:
struct Concept {
virtual ~Concept() = 0;
virtual void* getObjPtr_() = 0;
};
template <typename T>
struct Obj : Concept {
Obj(T O) : Data(std::move(O)) {}
void* getObjPtr_() { return static_cast<void*>(&Data); }

T Data;
};

std::unique_ptr<Concept> Self;
};

int main() {
ObjWrap a(1);
ObjWrap b(std::string("b"));
int* p_a = a.getObjPtr<int>();
std::string* p_b = b.getObjPtr<std::string>();

std::cout << *p_a << " " << *p_b << "\n";

return 0;
}

此版本代码与上面版本的主要区别在于 T * getObjPtr()是由 ObjWrap 封装的成员函数对象。

编辑 3:

我关于类型删除的问题已被接受的答案回答。然而,关于多个模板的同时类型实例化的问题还有待回答。我的猜测是目前 C++ 不允许这样做,但很高兴听到在这方面有更多经验的人的意见。

最佳答案

有几件事可能会有所帮助。

首先要说的是,如果 Obj 需要暴露对象的地址,那不是 Sean Parent 的“继承是万恶之源”类型删除容器。

诀窍是确保 Obj 的接口(interface)提供包装器永远需要的所有语义操作和查询。

为了提供这一点,在概念中缓存对象的地址及其 type_id 通常是一个合理的想法。

考虑以下更新的示例,其中有一个公共(public)方法 - operator==。规则是,如果两个 Obj 包含相同类型的对象并且这些对象比较相等,则它们相等。

注意地址和type_id:

1) 是实现细节,不暴露在 Obj 的接口(interface)上

2) 无需虚拟调用即可访问,这会短路不相等的情况。

#include <memory>
#include <utility>
#include <typeinfo>
#include <utility>
#include <cassert>
#include <iostream>

class ObjWrap
{
public:
template <typename T>
ObjWrap(T O) : Self(new Model<T>(std::move(O))) {}

// objects are equal if they contain the same type of model
// and the models compare equal
bool operator==(ObjWrap const& other) const
{
// note the short-circuit when the types are not the same
// this means is_equal can guarantee that the address can be cast
// without a further check
return Self->info == other.Self->info
&& Self->is_equal(other.Self->addr);
}

bool operator!=(ObjWrap const& other) const
{
return !(*this == other);
}

friend std::ostream& operator<<(std::ostream& os, ObjWrap const& o)
{
return o.Self->emit(os);
}

private:
struct Concept
{
// cache the address and type here in the concept.
void* addr;
std::type_info const& info;

Concept(void* address, std::type_info const& info)
: addr(address)
, info(info)
{}

virtual ~Concept() = default;

// this is the concept's interface
virtual bool is_equal(void const* other_address) const = 0;
virtual std::ostream& emit(std::ostream& os) const = 0;
};

template <typename T>
struct Model : Concept
{
Model(T O)
: Concept(std::addressof(Data), typeid(T))
, Data(std::move(O)) {}

// no need to check the pointer before casting it.
// Obj takes care of that
/// @pre other_address is a valid pointer to a T
bool is_equal(void const* other_address) const override
{
return Data == *(static_cast<T const*>(other_address));
}

std::ostream& emit(std::ostream& os) const override
{
return os << Data;
}

T Data;
};


std::unique_ptr<Concept> Self;
};


int main()
{
auto x = ObjWrap(std::string("foo"));
auto y = ObjWrap(std::string("foo"));
auto z = ObjWrap(int(2));

assert(x == y);
assert(y != z);

std::cout << x << " " << y << " " << z << std::endl;
}

http://coliru.stacked-crooked.com/a/dcece2a824a42948

关于c++ - 有没有办法在 C++ 中同时为多个模板分配一个类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51849975/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com