Я пытаюсь создать объект функции, в котором по указателю на член он вызывает std::hash члена, на который указывает (или результат вызова члена функции), но что-то не так с частичными специализациями, и это не так. t скомпилировать:
#include <iostream>
#include <utility>
template<auto MemberPtr>
struct hash_member_t;
template<class R, class C>
struct hash_member_t<R C::*Member>
{
constexpr std::size_t operator()(C const& a) const noexcept
{ return std::hash<R>{}(a.*Member); }
};
template<class R, class C>
struct hash_member_t<R (C::*Member)()>
{
constexpr std::size_t operator()(C const& a) const noexcept
{ return std::hash<R>{}(a.*Member()); }
};
template<auto Member>
inline constexpr hash_member_t hash_member = hash_member_t<Member>{};
struct A
{
int* a = nullptr;
};
int main(int, char**)
{
A a;
std::cout << hash_member<&A::a>(a) << '\n';
return 0;
}
Ошибка компиляции:
main.cpp:8:34: error: template argument 1 is invalid
8 | struct hash_member_t<R C::*Member>
| ^
main.cpp:15:38: error: template argument 1 is invalid
15 | struct hash_member_t<R (C::*Member)()>
| ^
main.cpp: In instantiation of 'constexpr const hash_member_t<...auto...> hash_member<&A::a>':
main.cpp:32:18: required from here
main.cpp:22:32: error: invalid use of incomplete type 'struct hash_member_t<&A::a>'
22 | inline constexpr hash_member_t hash_member = hash_member_t<Member>{};
| ^~~~~~~~~~~
main.cpp:5:8: note: declaration of 'struct hash_member_t<&A::a>'
5 | struct hash_member_t;
| ^~~~~~~~~~~~~
Вышеупомянутое скомпилировано с помощью g++. С clang++:
main.cpp:8:28: error: type-id cannot have a name
struct hash_member_t<R C::*Member>
^~~~~~
main.cpp:8:22: error: template argument for non-type template parameter must be an expression
struct hash_member_t<R C::*Member>
^~~
main.cpp:4:15: note: template parameter is declared here
template<auto MemberPtr>
^
main.cpp:15:28: error: expected unqualified-id
struct hash_member_t<R (C::*Member)()>
^
main.cpp:15:29: error: use of undeclared identifier 'Member'
struct hash_member_t<R (C::*Member)()>
^
main.cpp:22:46: error: implicit instantiation of undefined template 'hash_member_t<&A::a>'
inline constexpr hash_member_t hash_member = hash_member_t<Member>{};
^
main.cpp:32:18: note: in instantiation of variable template specialization 'hash_member' requested here
std::cout << hash_member<&A::a>(a) << '\n';
^
main.cpp:5:8: note: template is declared here
struct hash_member_t;
^
5 errors generated.
Что не так с синтаксисом или контекстом использования?
@463035818_is_not_an_ai Вы правы, специализация должна быть реальным адресом. Спасибо.
struct hash_member_t<R C::*Member> и struct hash_member_t<R (C::*Member)()> предоставляют типы, но шаблон ожидает объект, поскольку основной шаблон представляет собой выведенный параметр шаблона, не являющийся типом.
Кстати, a.*Member() должно быть (a.*Member)(), поскольку оператор вызова функции имеет более высокий приоритет, чем оператор указателя на член.





Вы путаете аргументы шаблона, не относящиеся к типу и типу.
Этот шаблон
template<auto MemberPtr> struct hash_member_t;
Имеет аргумент, не являющийся типом. Позже вы попытаетесь специализировать его для типов. Я полагаю, что есть более приятный способ написать это, это именно то, что я получил после исправления вашего кода:
#include <iostream>
#include <utility>
template <typename T,T member> struct hash_member_impl;
template<class R, class C,R C::*member>
struct hash_member_impl<R C::*,member>
{
constexpr std::size_t operator()(C const& a) const noexcept
{ return std::hash<R>{}(a.*member); }
};
template<class R, class C,R (C::*member)()>
struct hash_member_impl<R (C::*)(),member>
{
constexpr std::size_t operator()(C const& a) const noexcept
{ return std::hash<R>{}(a.*member()); }
};
template<auto MemberPtr>
using hash_member = hash_member_impl<decltype(MemberPtr),MemberPtr>;
struct A
{
int* a = nullptr;
};
int main(int, char**)
{
A a;
std::cout << hash_member<&A::a>{}(a) << '\n';
return 0;
}
Важная линия это
template<auto MemberPtr>
using hash_member = hash_member_impl<decltype(MemberPtr),MemberPtr>;
Ваш аргумент является значением, но вы хотите специализироваться на его типе, и именно так вы получаете и тип, и значение из аргумента auto, не являющегося типом.
Как указывалось в комментариях и принятом ответе, проблема заключалась в том, что параметр шаблона является значением, и поэтому частичная специализация требует фактического значения, например фактического указателя на член, но я намеревался определить тип получен указатель.
Для тех, у кого похожая проблема и кто хочет увидеть другие способы решения проблемы, я наконец использовал для себя следующее решение:
#include <iostream>
#include <utility>
template<auto MemberPtr>
struct hash_member_t
{
template<class T>
constexpr std::size_t operator()(T const& a) const noexcept
{ return _call(a, MemberPtr); }
private:
template<class R, class C>
constexpr std::size_t _call(C const& a, R C::*) const noexcept
{ return std::hash<R>{}(a.*MemberPtr); }
template<class R, class C>
constexpr std::size_t _call(C const& a, R (C::*)() const) const noexcept
{ return std::hash<R>{}((a.*MemberPtr)()); }
template<class R, class C>
constexpr std::size_t _call(C const& a, R (C::*)() const noexcept) const noexcept
{ return std::hash<R>{}((a.*MemberPtr)()); }
};
template<auto Member>
inline constexpr hash_member_t hash_member = hash_member_t<Member>{};
struct A
{
int a = 8;
std::string f() const noexcept { return "hi"; }
};
int main(int, char**)
{
A a;
std::cout << hash_member<&A::a>(a) << ' ' << hash_member<&A::f>(a) << '\n';
return 0;
}
Напечатается «8 11290347552884584064».
вы смешиваете аргументы шаблона, не относящиеся к типу и типу