我希望创建 std::type_index
的替代方案不需要RTTI :
template <typename T>
int* type_id() {
static int x;
return &x;
}
注意,局部变量x
的地址被用作类型ID,而不是x
本身的值。另外,我不打算在现实中使用裸指针。我刚刚删除了与我的问题无关的所有内容。查看我实际的 type_index
实现 here .
这种方法合理吗?如果可行,为什么?如果不是,为什么不呢?我觉得我在这里摇摇欲坠,所以我对我的方法行得通或行不通的确切原因很感兴趣。
一个典型的用例可能是在运行时注册例程以通过单个接口(interface)处理不同类型的对象:
class processor {
public:
template <typename T, typename Handler>
void register_handler(Handler handler) {
handlers[type_id<T>()] = [handler](void const* v) {
handler(*static_cast<T const*>(v));
};
}
template <typename T>
void process(T const& t) {
auto it = handlers.find(type_id<T>());
if (it != handlers.end()) {
it->second(&t);
} else {
throw std::runtime_error("handler not registered");
}
}
private:
std::map<int*, std::function<void (void const*)>> handlers;
};
这个类可以这样使用:
processor p;
p.register_handler<int>([](int const& i) {
std::cout << "int: " << i << "\n";
});
p.register_handler<float>([](float const& f) {
std::cout << "float: " << f << "\n";
});
try {
p.process(42);
p.process(3.14f);
p.process(true);
} catch (std::runtime_error& ex) {
std::cout << "error: " << ex.what() << "\n";
}
结论
感谢大家的帮助。我已经接受了@StoryTeller 的回答,因为他概述了为什么解决方案应该根据 C++ 的规则是有效的。然而,@SergeBallesta 和评论中的其他一些人指出,MSVC 执行的优化非常接近于打破这种方法。如果需要更强大的方法,那么使用 std::atomic
的解决方案可能更可取,正如@galinette 所建议的那样:
std::atomic_size_t type_id_counter = 0;
template <typename T>
std::size_t type_id() {
static std::size_t const x = type_id_counter++;
return x;
}
如果有人有进一步的想法或信息,我仍然渴望听到它!
最佳答案
是的,它在一定程度上是正确的。模板函数隐含 inline
, 和 inline
中的静态对象功能在所有翻译单元之间共享。
因此,在每个翻译单元中,您将获得相同静态局部变量的地址,以调用 type_id<Type>()
。 .您在此处受到标准保护,不会违反 ODR。
因此,本地静态的地址可以作为一种自制的运行时类型标识符。
关于c++ - 在函数模板中使用静态局部变量的地址作为类型标识符是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41868077/