Можно ли использовать std::hash для указателей хеш-функций?

Можно ли использовать тип С++ 11 std::hash для указателей хеш-функций? Существует hash частичная специализация, определяемая как

template <typename T> struct hash<T*>;

но поскольку указатели функций отличаются от других типов указателей в C++ (например, они не могут быть приведены к void*), я не уверен, безопасно ли использовать его для таких типов, как int(*)() или void(*)(int, int).

Это разрешено? Есть ли в новой спецификации ISO какая-либо конкретная формулировка, которая поддерживает или опровергает это?

Спасибо!


person templatetypedef    schedule 01.11.2013    source источник
comment
Это просто теоретически? Я не думаю, что хэш-функция по умолчанию для указателей на функции имеет какое-либо практическое применение, поскольку (в большинстве реализаций) она просто хеширует целое число, лежащее в основе указателя.   -  person Siyuan Ren    schedule 01.11.2013
comment
@C.R.- Это частично теоретически, хотя мне также любопытно, можете ли вы сделать что-то вроде std::unordered_map<void(*)(), std::string>, которое могло бы быть обратной картой от строк к функциям или что-то в этом роде.   -  person templatetypedef    schedule 01.11.2013
comment
Я провел здесь несколько тестов и увидел, что указатели функций успешно приводятся к void*.   -  person Murilo Vasconcelos    schedule 01.11.2013
comment
@MuriloVasconcelos для вашей конкретной реализации, да. Но стандарт не дает никаких гарантий.   -  person Tristan Brindle    schedule 01.11.2013
comment
Хотя это строго незаконно, я осмелюсь сказать, что это должно работать, потому что указатели функций на одну и ту же функцию гарантированно будут сравниваться как равные, а указатели функций на другую функцию должны сравниваться не как равные. Это каким-то образом подразумевает, что каждая функция — это отдельная штука, независимо от того, что это такое. Таким образом, если хэш стоит своей соли, он должен иметь уникальное значение.   -  person Damon    schedule 04.11.2013
comment
@C.R., почему это практически бесполезно? Это означает, что каждая функция будет хэшировать до отдельного значения, давая идеальный хэш.   -  person Jonathan Wakely    schedule 04.11.2013
comment
@JonathanWakely: я ошибался. Я думал, что хорошее хеширование должно сопоставлять связанные входные данные с, казалось бы, случайными выходными данными, и забыл, что конечной целью является предотвращение коллизий.   -  person Siyuan Ren    schedule 06.11.2013


Ответы (3)


Отличный вопрос. Я не знаю точного ответа, и я буду рад обратиться к любому, кто знает лучше меня, но я думаю, что хотя указатели на функции и не то же самое, что указатели на данные, тем не менее они являются указателями: так что std::hash<T*> следует применять частичную специализацию.

Что бы это ни стоило, следующее компилируется без предупреждений даже с -pendantic в g++ 4.8.1 и clang 3.3 и работает как положено:

#include <functional>
#include <iostream>

void func1(int) {}
void func2(int) {}

int main()
{
    typedef void (*func_type) (int);

    std::hash<func_type> hash;

    std::cout << hash(func1) << std::endl;
    std::cout << hash(func2) << std::endl;

}

Мне было бы очень интересно, если бы у кого-нибудь были ссылки на стандарт, подтверждающие это.

person Tristan Brindle    schedule 01.11.2013
comment
Умные указатели определенно охватываются стандартом ([util.smartptr.hash] 20.7.2.6). Все еще смотрите, есть ли указатели кода. - person WhozCraig; 01.11.2013
comment
Ничто в стандарте не говорит, что hash<T*> не применимо к любому типу указателя, поэтому оно применимо. В частности, это относится к любым указателям на void или объектам или функциям (включая статические члены классов) заданного типа (различные типы указателей, указанные в [basic.compound]). - person Jonathan Wakely; 04.11.2013

Я нашел следующее:

17.6.3.4 Требования к хешу

Тип H соответствует требованиям к хэшу, если:

  • это тип объекта функции (20.8)

[...]

И затем в упомянутом 20.8 говорится:

Тип объекта функции — это тип объекта (3.9), который может быть типом постфиксного выражения в вызове функции (5.2.2, 13.3.1.1)228. Объект функции — это объект типа объекта функции. В тех местах, где можно было бы ожидать передачи указателя на функцию в алгоритмический шаблон (раздел 25), указывается, что интерфейс принимает объект функции. Это не только заставляет алгоритмические шаблоны работать с указателями на функции, но также позволяет им работать с произвольными объектами функций.

Это как бы утверждает обратное... но утверждение не только заставляет алгоритмические шаблоны работать с указателями на функции... кажется подходящим для вашего вопроса.

person Escualo    schedule 08.11.2013
comment
В вопросе не используются какие-либо параметры шаблона не типа. T — это параметр типа. - person AnT; 08.11.2013
comment
@AndreyT Mhhh ... Я либо неправильно читаю, либо неправильно понимаю стандарт ... не хочешь объяснить? - person Escualo; 08.11.2013
comment
Это довольно просто. Существует три типа параметров шаблона: #1) параметры типа, например. template <typename T> ..., #2) нетиповые параметры, например. template <int N> ..., #3) параметры шаблона, например. template <template <typename U> class C> .... В данном случае мы имеем дело с обычным параметром type (#1). Между тем, вы предоставили цитату, которая относится конкретно к параметрам нетипового (№ 2). Так что я просто не понимаю, как ваша цитата уместна здесь. - person AnT; 08.11.2013
comment
Спасибо. Я буду изменять соответственно. - person Escualo; 08.11.2013
comment
Этот абзац не про (какой-то выдуманный) Hashable, а про Hash. Он определяет, какие типы могут использоваться для хеширования, а не какие типы могут быть хешированы. ОП спрашивает, можно ли использовать некоторую специализацию std::hash (соответствующую требованиям Hash) для хеширования указателя на функцию; нет, если указатели функций соответствуют требованиям Hash. - person dyp; 08.11.2013

Это действительно интересно... Я столкнулся с этим вопросом при использовании MSVC++. Я пытаюсь сделать следующее:

static std::unordered_map<Fun, std::string> FunctionMap()
{
    static std::unordered_map<Fun, std::string> map;
    return map;
}

с Fun тип указателя на функцию.

Во время компиляции получаю следующую ошибку:

error C2338: The C++ Standard doesn't provide a hash for this type.
....
_Kty=int (__thiscall Testje::* )(int,int)

В предыдущей попытке я попытался привести указатель функции к void*, что не разрешено и не компилируется (см.: https://isocpp.org/wiki/faq/pointers-to-members#cant-cvt-memfnptr-to-voidptr для подробностей) . Причина в том, что void* — это указатель на данные, а указатель на функцию — это указатель на код.

Мой вывод на данный момент заключается в том, что это не разрешено и не будет компилироваться в MSVC++.

person atlaste    schedule 22.04.2015
comment
Это не имеет к этому никакого отношения. Указатель на функцию-член ни в малейшей степени не является указателем на функцию. - person Puppy; 07.11.2015