gpt4 book ai didi

c++ - 使用模板函数安全地在多个类类型之间进行转换

转载 作者:行者123 更新时间:2023-11-28 02:09:17 38 4
gpt4 key购买 nike

我正在使用的第三方库要求将指针作为 void* 传递。在任何给定时间,都可能需要将此指针强制转换为继承链中的几个类之一。当涉及多重继承时,这会失败,因此我设计的安全发生这种情况的方法是将类类型与指针一起传播,以便正确地转换为所需的类型。以下演示了预期目标:

#include <assert.h>
#include <stdint.h>
#include <cstddef>
#include <stdio.h>

enum class kTypeFlag { PARENTONE, PARENTTWO, CHILD };

#define CAST_TO_CLASS_TYPE(TO, FROM, POINTER) \
dynamic_cast<TO*>(static_cast<FROM*>(POINTER))

class ParentOne {
public:
ParentOne() { }
virtual ~ParentOne() { }
virtual size_t byte_size() const = 0;
};

class ParentTwo {
public:
ParentTwo(uint32_t id) : id_(id) { }
virtual ~ParentTwo() { }
uint32_t id() const { return id_; }
private:
const uint32_t id_;
};

class Child : public ParentOne, public ParentTwo {
public:
Child(uint32_t id) : ParentOne(), ParentTwo(id) { }
virtual ~Child() { }
size_t byte_size() const override { return sizeof(*this); }
};

template <class T>
T* Convert(void* pointer, kTypeFlag flag) {
switch (flag) {
case kTypeFlag::PARENTONE:
return CAST_TO_CLASS_TYPE(T, ParentOne, pointer);
case kTypeFlag::PARENTTWO:
return CAST_TO_CLASS_TYPE(T, ParentTwo, pointer);
case kTypeFlag::CHILD:
return CAST_TO_CLASS_TYPE(T, Child, pointer);
default:
assert(0 && "invalid flag to Convert");
}
}

int main() {
Child* child = new Child(5);
printf("byte_size: %zu\n", child->byte_size());
printf("id: %u\n", child->id());

ParentOne* p1 = Convert<ParentOne>(child, kTypeFlag::CHILD);
ParentTwo* p2 = Convert<ParentTwo>(child, kTypeFlag::CHILD);
printf("byte_size: %zu\n", p1->byte_size());
printf("id: %u\n", p2->id());
}

请注意,CAST_TO_CLASS_TYPE 使用 dynamic_cast 而不是 static_cast。这是因为如果使用 static_cast,构建将失败并显示:

run.cc:40:14: error: static_cast from 'ParentTwo *' to 'ParentOne *', which are not related by inheritance, is not allowed
return CAST_TO_CLASS_TYPE(T, ParentTwo, pointer);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
run.cc:9:3: note: expanded from macro 'CAST_TO_CLASS_TYPE'
static_cast<TO*>(static_cast<FROM*>(POINTER))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
run.cc:53:19: note: in instantiation of function template specialization 'Convert<ParentOne>' requested here
ParentOne* p1 = Convert<ParentOne>(child, kTypeFlag::CHILD);
^

所以我的问题是:为什么在使用 static_cast 时构建会失败?还是有其他方法可以完全做到这一点?最终目标是围绕需要将 void* 强制转换为几种不同类型来强制执行某种类型安全。我不关心这是如何完成的。以上只是我能想到的最好的。

编辑:请允许我澄清一下为什么使用 dynamic_cast 并不理想。以下代码段可以正常编译:

ParentTwo* p2 = new ParentTwo(42);
ParentOne* p1 = Convert<ParentOne>(p2, kTypeFlag::PARENTTWO);
printf("id: %u\n", p2->id());
printf("byte_size: %zu\n", p1->byte_size());

但它会在运行时中止。最好这会在编译时被捕获。这就是为什么我想使用 static_cast,但由于上面解释的原因是不可能的。

最佳答案

您已经在评论中得到了为什么您的代码不起作用的解释。您似乎想要一个替代方案,所以就在这里。

http://ideone.com/24iaNv

namespace details
{
template<typename To, kTypeFlag>
struct cex {To* operator()() { static_assert(!std::is_same<To, To>::value, "invalid flag to Convert");} };
template<typename To>
struct cex<To, kTypeFlag::PARENTONE> { To* operator()(void*p) { return static_cast<To*>(static_cast<ParentOne*>(p)); } };
template<typename To>
struct cex<To, kTypeFlag::PARENTTWO> { To* operator()(void*p) { return static_cast<To*>(static_cast<ParentTwo*>(p)); } };
template<typename To>
struct cex<To, kTypeFlag::CHILD> { To* operator()(void*p) { return static_cast<To*>(static_cast<Child*>(p)); } };
};

template <typename T, kTypeFlag f>
T* ConvertEx (void* pointer) { return details::cex<T, f>()(pointer); }

关于c++ - 使用模板函数安全地在多个类类型之间进行转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36324407/

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