c++ - 在函数模板中使用静态局部变量的地址作为类型标识符是否安全?

标签 c++ templates language-lawyer rtti

我希望创建 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/

相关文章:

C++ - 命名空间与静态函数

c++ - 可以从 QXmlStreamWriter 获取 QDomElement 吗?

c++ - 如何将 A<B<T>>* 解释为 A<C<T>>* 其中 B : public C<T>?

C++ 标准 : do namespace-scoped constexpr variables have internal linkage?

c++ - 如何解密被 CryptProtectData 函数加密的数据?

c++ - 设计生成所有 n 位数字组合的递归函数的最佳方法是什么?

c++ - 返回 C++17 可变参数模板的可变参数聚合(结构)和语法 'construction deduction guide'

c++ - 模板化重载运算符的编译错误 "No global operator found"

c++ - c++20中类模板构造函数可以有冗余模板参数列表吗

连续分配与顺序分配