Как определить шаблонную функцию с двумя относительными параметрами

#c #templates #functor

#c #шаблоны #функтор

Вопрос:

Я пытаюсь определить функцию, которая позволяет нам вызывать стандартную хэш-функцию или какую-либо пользовательскую функцию и возвращать значение hash .

Вот пример использования моей функции:

 auto res = myfunc<std::hash>(2);    //hash the integer 2 with the function std::hash
auto res2 = myfunc<std::hash>("abc");    // hash the string "abc" with the function std::hash
auto res3 = myfunc<customHasher>(2);    // hash the integer 2 with some custom hash function
 

Я попытался закодировать, как показано ниже:

 template<void (*T)(U)>
size_t myfunc(const U amp;u)
{
    return T<U>(u);
}
 

T должен быть указатель на функцию, a std::function или лямбда, и U является типом параметра T .

Но она не может быть скомпилирована.

 main.cpp:14:23: error: expected ‘>’ before ‘(’ token
     template<void (*T)(U)>
                       ^
main.cpp:15:25: error: ‘U’ does not name a type
     size_t myfunc(const U amp;u)
                         ^
main.cpp: In function ‘size_t myfunc(const intamp;)’:
main.cpp:17:18: error: ‘U’ was not declared in this scope
         return T<U>(u);
 

Ну, я знаю, что template<void (*T)(U)> это должно быть неправильно, потому U что не определено. Но я не знаю, как это исправить.

Комментарии:

1. std::hash не является функцией. Исправление вашей попытки указателя на функцию (при условии, что это возможно) все равно не продвинет вас намного дальше.

2. @StoryTeller-UnslanderMonica ХОРОШО, я добавил одну строку в свой пост: «T должен быть указателем на функцию, std::function или лямбда, а U — тип параметра T.».

3. это customhasher шаблон? return T<U>(u); предполагает, что T это шаблон, это необходимо или вы могли бы передать, например std::hash<int> ?

4. @largest_prime_is_463035818 Да, customhasher похож std::hash на шаблон с одним параметром.

5. @largest_prime_is_463035818 В этом и суть. Видите ли, я не хочу передавать std::hash<int> , я просто хочу просто передать std::hash .

Ответ №1:

Вам нужно объявить оба параметра. Более того, std::hash это шаблон класса, а не функция. Вы можете использовать параметр шаблона шаблона:

 #include <cstdint>
#include <functional>
#include <iostream>
#include <string>

template<typename T, template<typename> typename H = std::hash>
std::size_t myfunc(const T amp;t)
{
    return H<T>{}(t);
}

int main() {
    std::cout << myfunc(std::string{"123"});
}
 

Хотя, чтобы использовать то же самое с вашим customHasher , он также должен быть шаблоном класса (with operator() ).

Обратите внимание, что вам нужно явно сконструировать строку в main , иначе T не может быть выведено, чтобы быть std::string .

Комментарии:

1. Круто, не знал этого. В C 17 есть это?

2. У @kabaus c 98 было это 😉

3. @Yves нет, потому что «abc» — это строковый литерал c, для которого нет специализации std::hash. вам нужно будет указать строку

4. @Yves Я не мастер шаблонов, но вы могли бы использовать перегрузку или специализацию, например, ссылку . Редактировать: забыл, что частичная специализация шаблона не допускается для шаблонов функций. Перегрузка, похоже, работает.

5. @Yves обратите внимание, что преобразование из c-string в std::string не является бесплатным. Вы могли бы изучить возможность использования std::hash<std::string_view> , который поддерживает несколько строковых форматов (но НЕ является владельцем)