- Могу ли я как-то опустить нечеткий указатель на член в экземпляре делегата, например: Delegate (obj)?
Согласно этому ответу ... я полагаю, что ответ "нет".
Мне лень, и указание подписи члена два раза кажется мне слишком сложным. Можем ли мы каким-то образом вывести сигнатуру шаблона на основе одного аргумента шаблона, поэтому Delegate (obj) становится Delegate <& Foo :: Bar> (obj)?
Вы пометили C ++ 17, так. .. да: вы можете использовать auto
template <auto>
class Delegate
{ };
template <typename T, typename R, typename... Args,
R (T::*TMember)(Args...)>
class Delegate<TMember>
// ...
template <typename T, typename R, typename... Args,
R (T::*TMember)(Args...) const>
class Delegate<TMember>
// ...
// ...
auto add = Delegate<&Foo::Bar>(obj);
// ...
auto const_add =
Delegate<&Foo::ConstBar>(const_obj);
Мне нужно специализировать обе версии - константную и неконстантную. Может ли компилятор сделать это для меня? Как насчет volatile / const volatile специализаций, должен ли я копировать один и тот же код снова и снова?
Может быть, добавить уровень косвенности?
Я имею в виду ... если высоздайте базовый класс для Delegate
следующим образом
template <auto TMember, typename T, typename R, typename ... Args>
class DelegateBase
{
public:
DelegateBase (T & obj) : obj_{obj}
{ }
R operator() (Args &&... args) const
noexcept
(noexcept((std::declval<T>().*TMember)(std::forward<Args>(args)...)))
{ return (obj_.*TMember)(std::forward<Args>(args)...); }
private:
T & obj_;
};
, который вы можете написать Delegate
, используя DelegateBase
template <auto>
class Delegate
{ };
template <typename T, typename R, typename... Args,
R (T::*TMember)(Args...)>
class Delegate<TMember>
: public DelegateBase<TMember, T, R, Args...>
{ using DelegateBase<TMember, T, R, Args...>::DelegateBase; };
template <typename T, typename R, typename... Args,
R (T::*TMember)(Args...) const>
class Delegate<TMember>
: public DelegateBase<TMember, T const, R, Args...>
{ using DelegateBase<TMember, T const, R, Args...>::DelegateBase; };
Полагаю, вы можете добавить пару volatile
/const volatile
специализаций.
Не по теме: если вы хотите использовать идеальную пересылку, вы должны использовать ссылки на пересылку, а не ссылки на r-значения.
Я имею в виду ... выне может использовать идеальную пересылку в вашем operator()
R operator()(Args &&... args) const noexcept(
noexcept((obj_.*TMember)(std::forward<Args>(args)...))) {
return (obj_.*TMember)(std::forward<Args>(args)...);
} // ....................^^^^^^^^^^^^^^^^^^ wrong
, потому что пакет Args...
- это переменный параметр класса, а не оператора;поэтому в operator()
Args && ... args
являются ссылками на r-значение (например, std::move
).
Если вы хотите использовать идеальную пересылку, вы должны использовать параметры шаблона самого operator()
, поэтому
template <typename ... As>
R operator()(As &&... args) const noexcept(
noexcept((obj_.*TMember)(std::forward<As>(args)...))) {
return (obj_.*TMember)(std::forward<As>(args)...);
} // ....................^^^^^^^^^^^^^^^^ ok