Предпосылки: У меня есть сценарий, в котором я должен допускать сравнение между двумя объектами-функторами, используя уникальный идентификатор для проверки, являются ли они равными (я не могу просто проверить, совпадают ли их адреса, поскольку сами указатели функций не являются хранится в объекте). Первоначально у меня была эта идея, чтобы просто запустить генератор id с 0 и увеличить до бесконечности:
struct GenerateUniqueID{
static std::size_t id_count = 0;
auto operator()() -> std::size_t { return (id_count++); }
};
... Тем не менее, поскольку у меня буквально тысячи и тысячи этих объектов создавались каждые несколько секунд, мне действительно удалось столкнуться с тем, что id_count переполнен до 0! Результаты были... неприятными. Теперь вторая идея заключалась в том, что, поскольку эти функторы, очевидно, обертывают вокруг функции, я мог бы выполнить сравнение, преобразовывая адрес указателя функции в 64-разрядное целое и сохраняя это в классе для сравнения, Видеть:
//psuedocode
struct Functor{
std::uint64_t id;
auto generate_id_from_function_address(function f) -> void {
id = reinterpret_cast<std::uint64_t>(&f);
}
};
Теперь, моя забота здесь проста: отличает ли указатели функций от 64-битных целых чисел неуправляемыми/неопределенными? На 32-битных архитектурах? На 64-битных архитектурах? На обоих? Моя главная проблема здесь в том, что с виртуальными функциями, поскольку я знаю, что для встроенных функций компилятор просто создает не-встроенную версию, поэтому там нет проблем.
Преобразование обычного указателя (не говоря уже о указателе функции) в uint64_t
определяется реализацией, поскольку указатели могут быть более широкими, чем 64 бита. Преобразование корректно определено, если вы используете uintptr_t
(и этот тип существует).
Преобразование указателя функции в любой целочисленный тип определяется реализацией (даже если вы используете uintptr_t
), поскольку указатели на функции могут быть более широкими, чем обычные указатели. Некоторые другие стандарты, такие как POSIX, явно разрешают это, поэтому в POSIX безопасно uintptr_t
указатели на указатели данных, такие как void*
и uintptr_t
.
(Преобразование указателя в элемент с целым числом, указателем данных или указателем регулярной функции не определено и на практике, вероятно, всегда будет терпеть неудачу, так как они больше обычных указателей.)
Тем не менее, может быть проще просто использовать uint64_t
вместо size_t
для ваших уникальных идентификаторов. В принципе невозможно uint64_t
, увеличивая его количество из-за их огромного диапазона.
converting the address of the function pointer into a 64-bit integer, and storing that in the class for comparison
Почему бы не сохранить действительный указатель на функцию?