Я предполагаю, что вы не поддерживаете volatile.
Вот 5 типов, которые могут быть в сигнатуре ваших указателей функций:
int
int const&
int &
int const&&
int &&
В вашем дизайне, вы не можете передать чистый int
in. Поэтому нам нужно беспокоиться об этом только как аргумент указателя функции.
int
может быть вызван любым из вышеперечисленных.
int const&
может быть вызван любым из вышеперечисленных.
int const&&
может быть вызван int&&
.
int&
, а int&&
не может быть вызван ничем другим.
Теперь, если наш тип является подвижным, но не копируемым, правила меняются.
T
можно вызвать только по T&&
.
T const&
все еще можновызывается кем-либо.
Если наш тип является неподвижным, то T
не может быть вызван через прокси-упаковщик без системы emplace
.
В точке вызова нам нужноинвертировать это.Если вызывается с T&
T const&
и T&
.Если T
можно скопировать, также проверьте T
.
Если вызывается с T const&
, мы проверяем только T const&
и T
, если T
можно скопировать.
Если вызывается с T&&
, нам нужно проверить T&&
и T const&&
и T const&
и T
, если T
можно переместить.
Если вызывается с T const&&
, мы проверяем только T const&&
и T
, если T
можно скопировать.
Так что это дает нам план атаки.
template<class T>
void populate(has_t hash, std::function<void(T)> f) {
signal_router<T>[hash] = std::move(f);
}
template<class T>
void attach(hash_t hash, void(*f)(T&)) {
populate<T&>(hash, f);
}
template<class T>
void attach(hash_t hash, void(*f)(const T&)) {
populate<T const&>(hash, f);
populate<T&>(hash, f);
populate<T&&>(hash, f);
populate<T const&&>(hash, f);
}
template<class T>
void attach(hash_t hash, void(*f)(T&&)) {
populate<T&&>(hash, f);
}
template<class T>
void attach(hash_t hash, void(*f)(T const&&)) {
populate<T&&>(hash, f);
populate<T const&&>(hash, f);
}
template<class T>
void attach(hash_t hash, void(*f)(T)) {
if constexpr( std::is_copy_constructible<T>{} ) {
populate<T const&>(hash, f);
populate<T&>(hash, f);
populate<T const&&>(hash, f);
}
if constexpr( std::is_move_constructible<T>{} ) {
populate<T&&>(hash, f);
}
}
, а emit:
template<class T>
void emit(hash_t hash, T&& param) {
try {
signal_router<T&&>[hash](param);
}
Для поддержки volatile
потребуется еще один проход.
При этом использовался некоторый C ++ 17;Есть способы обойти if constexpr
.Я бы использовал диспетчеризацию тегов.