Подтвердить что ты не робот

Указательные классы и оператор → *

Недавно я столкнулся с необходимостью применения указателя к элементу к объекту, указанному итератором. Я пробовал естественный синтаксис:

ite->*ptr = 42;

К моему ужасу, он не скомпилировался. Итераторы не перегружают operator->*, но более удивительно не делают интеллектуальных указателей. Мне нужно было прибегнуть к следующей болтовне:

(*ite).*ptr = 42;

Эксперимент (см. приведенный ниже пример) показал, что такой синтаксис, по-видимому, доступен для пользовательских классов как для указателей-для-членов, так и для указателей-членов-членов, по крайней мере, с С++ 14.

Таким образом:

  • Есть ли причина, по которой стандартные классы-указатели не перегружают operator->*, или это просто недосмотр?
  • Должен ли я перегружать operator->* при определении моих собственных классов, похожих на указатель, или же эта же причина применима ко мне?

Живой пример - что компилирует, что нет, и доказательство концепции для пользовательского класса.

4b9b3361

Ответ 1

Вы можете перегрузить ->* с помощью бесплатной функции. Он не должен быть членом.

template <typename P,
          typename T,
          typename M>
M& operator->* (P smartptr, M T::*ptrmem)
{
    return (*smartptr).*ptrmem;
}

Теперь все, что имеет унарные operator*, определенные (итераторы, интеллектуальные указатели, любые), также может использовать ->*. Возможно, вы захотите сделать это немного более контролируемым образом, то есть определить его для известных итераторов, известных интеллектуальных указателей и т.д. Отдельно.

Это не будет работать для функций-членов по понятным причинам. Нужно специализироваться/перегружать для этого случая и вместо этого возвращать std::function:

template <typename P,
          typename T,
          typename M,
          typename ... Arg>
std::function<M(Arg&&...)> 
operator->* (P smartptr, M (T::*ptrmem)(Arg... args))
{
    return [smartptr,ptrmem](Arg&&... args) -> M 
      { return ((*smartptr).*ptrmem)(std::forward<Arg>(args)...); };
}

Ответ 2

Это то, что вы хотите сделать ((&*ite)->*ptr) = 42;?