2015-08-06 8 views
14

Recentemente ho riscontrato la necessità di applicare un puntatore a membro all'oggetto designato da un iteratore. Ho provato la sintassi naturale:Classi simili a puntatori e l'operatore -> *

ite->*ptr = 42; 

Con mio disappunto, non ha compilato. Gli iteratori non sovraccaricano operator->*, ma più sorprendentemente non fanno puntatori intelligenti. Avevo bisogno di ricorrere al seguente clunkiness:

(*ite).*ptr = 42; 

sperimentazione (si veda l'esempio vivo di seguito) ha dimostrato che una tale sintassi sembra essere realizzabile per classi personalizzate, sia per i puntatori-a-membri e puntatori-to funzioni membro, almeno dal C++ 14.

Così:

  • C'è un motivo per le classi di puntatore come standard non sovraccaricare operator->*, o è solo una svista?
  • In caso di sovraccarico di operator->* quando si definiscono le mie classi puntatore-simili o si applica lo stesso motivo?

Live example - cosa compila, cosa no e un proof-of-concept per una classe personalizzata.

+1

@Galik faccio membri puntatori-a-dire, non membri di pianura. Dai un'occhiata [qui] (http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_data_members). – Quentin

+0

Ottima domanda. +1. – Nawaz

+0

vedere http://stackoverflow.com/questions/14106975/error-in-using-unique-ptr-with-member-function-pointer vengono fatti alcuni buoni punti – Hcorg

risposta

5

È possibile sovraccaricare ->* con una funzione gratuita. Non deve essere un membro.

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

Ora tutto ciò che ha unari operator* definiti (iteratori, puntatori intelligenti, quale che sia) può anche utilizzare ->*. Potresti volerlo fare in modo un po 'più controllato, cioè definirlo separatamente per iteratori noti, noti puntatori intelligenti ecc.

Questo non funzionerà per le funzioni membro per ovvi motivi. Uno avrebbe bisogno di specializzarsi/sovraccarico per questo caso e restituire un balzo std::function invece:

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)...); }; 
} 
0

E 'questo quello che vuoi fare ((&*ite)->*ptr) = 42;?

+0

Siamo spiacenti. È che '((& * ite) -> * ptr) = 42;'? –

+0

Questo funziona, ma è in particolare il work-around che mi piacerebbe non dover usare.Si noti che la domanda non riguarda un problema pratico da risolvere, ma perché non può essere risolto con una sintassi naturale, anche se è tecnicamente possibile ottenere tale sintassi. – Quentin

+0

In effetti esiste una sintassi naturale 'ite -> * ptr = 42;' questo sta chiamando il membro della classe iteratore. Se sovraccarichi l'operatore, non puoi usarlo per chiamare membri dell'iteratore. Ecco perché non lo è. –