I wish to create an alternative to std::type_index
that does not require RTTI:
template <typename T>
int* type_id() {
static int x;
return &x;
}
Note that the address of the local variable x
is used as the type ID, not the value of x
itself. Also, I don't intend to use a bare pointer in reality. I've just stripped out everything not relevant to my question. See my actual type_index
implementation here.
Is this approach sound, and if so, why? If not, why not? I feel like I am on shaky ground here, so I am interested in the precise reasons why my approach will or will not work.
A typical use case might be to register routines at run-time to handle objects of different types through a single 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;
};
This class might be used like so:
processor p;
p.register_handler<int>([](int const& i) {
std::cout << "int: " << i << "
";
});
p.register_handler<float>([](float const& f) {
std::cout << "float: " << f << "
";
});
try {
p.process(42);
p.process(3.14f);
p.process(true);
} catch (std::runtime_error& ex) {
std::cout << "error: " << ex.what() << "
";
}
Conclusion
Thanks to everyone for your help. I have accepted the answer from @StoryTeller as he has outlined why the solution should be valid according the rules of C++. However, @SergeBallesta and a number of others in the comments have pointed out that MSVC performs optimizations which come uncomfortably close to breaking this approach. If a more robust approach is needed, then a solution using std::atomic
may be preferable, as suggested by @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;
}
If anyone has further thoughts or information, I am still eager to hear it!
question from:
https://stackoverflow.com/questions/41868077/is-it-safe-to-use-the-address-of-a-static-local-variable-within-a-function-templ 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…