2015-09-25 29 views
10

Perché il operator() del prefisso stateless non può essere static? Gli oggetti lambda stateless sono convertibili in puntatori a funzioni libere aventi la stessa firma del loro operator().Perché l'operatore() del functor stateless non può essere statico?

Stephan T. Lavavej a pag. 6 sottolinea che la conversione a un puntatore di funzione è solo un operator FunctionPointer() (citare). Ma non riesco a ottenere un puntatore corrispondente a operator() come a una funzione non membro. Per il functor struct F { void operator()() {} } sembra impossibile convertire &F::operator() in istanza di tipo using P = void (*)();.

Codice:

struct L 
{ 
    static 
    void operator()() const {} 
    operator auto() const 
    { 
     return &L::operator(); 
    } 
}; 

L'errore è

'operatore()' sovraccarico non può essere una funzione membro static

ma operator() non è sovraccarico.

+4

Se la tua classe di functor è senza stato, qual è il punto di avere una classe piuttosto che una semplice funzione? –

+3

Tutte le funzioni 'operator' di una classe sono considerate" operatori sovraccaricati " –

+0

@ πάνταῥεῖ Non ha importanza nel senso di questa domanda (non pratica). Se il mio codice è una libreria, dovrei essere in grado di mantenere tutti i tipi possibili forniti dall'utente. – Orient

risposta

10

Per standard di 13,5/6,

Una funzione operatore deve essere o una funzione membro non statico o essere una funzione non membro e hanno almeno un parametro il cui tipo è una classe, un riferimento a una classe, un'enumerazione o un riferimento a un'enumerazione .

Inoltre, in 13.5.4 si afferma che

operatore() è una funzione membro non statica con un numero arbitrario di parametri. Può avere argomenti predefiniti . Implementa la funzione di chiamata sintassi postfissa-espressione ( espressione-list opt ) dove il postfissa espressione restituisce un oggetto di classe e eventualmente vuota espressione-list corrispondenze la lista dei parametri di un operatore() funzione membro della classe. Pertanto, una chiamata x (arg1, ...) viene interpretato come x.operator() (arg1, ...) per un oggetto classe x di tipo T

+3

Ma quale è la ragione logica per questo? Ad ogni modo dovrei accettare la risposta a causa della mia povera formulazione di domande =). – Orient

+0

@Orien Qui gli utenti potrebbero essere in grado di indovinare il loro ragionamento, ma per una risposta definitiva a questa domanda, penso che dovresti dirigerlo al Comitato. – user2079303

+0

@Orient, direi che la ragione logica è che tutti gli operatori dovrebbero comportarsi allo stesso modo. Anche il richiamo di un operatore per un _class_ invece di un oggetto non sembra giusto. Sfortunatamente non so quali siano le ragioni precise del comitato diretto da quando stavano facendo lo standard. – SingerOfTheFall

4

I penserei che non ci siano ragioni tecniche per proibirlo (ma non avendo familiarità con il cross-vendor di fatto C++ ABI (Itanium ABI), non posso promettere nulla).

C'è tuttavia un problema evolutivo a questo riguardo a https://cplusplus.github.io/EWG/ewg-active.html#88. Ha anche il [minuscolo] segno su di esso, rendendolo una caratteristica un po '"banale" in esame.

+1

Penso che il vero significato del * "minuscolo" * qui significhi che il * comitato * ha capito di aver fatto un * errore *, e che prova a mostrarlo come sarebbe solo un * minuscolo * Non avere illusioni: se l'unica ragione possibile è che nessuno nel comitato è un programmatore C++ competente. – peterh

1

Un semplice, una soluzione sporca po 'fino a quando il relativo comitato considera questa caratteristica banale:

operatori Glob sono sintatticamente simili ai costruttori.

Quindi, non è possibile scrivere un

static MyClass::operator()(...); 

E 'stato fatto semplicemente impossibile, a causa di un comitatodeciso così via motivi non chiari. Sarei così felice se potessi parlare con uno dei loro membri, per chiedere, cosa avevano in mente quando lo avessero deciso. Sfortunatamente, probabilmente non avrebbe capito la mia domanda, perché non ha mai programmato il C++. Ha lavorato solo sui suoi documenti.

Ora hanno bisogno di alcuni decenni di

  • dibattiti
  • consultazioni
  • incontri
  • e considerazioni

per implementare una funzione banale. Sospetto che la funzione possa essere resa disponibile in C++ 3x, e su macchine emulate potrebbe essere persino provata.

Fino ad allora, si può provare a scrivere:

MyClass::MyClass(...); 

In entrambi i casi è possibile chiamare MyClass(...);.

Ovviamente è utile principalmente se MyClass è un singleton. E, direi che è un hack. Inoltre, alloca uno stack sizeof(MyClass) che potrebbe essere negativo per prestazioni/efficienza.


Inoltre, questo sarà essenzialmente un costruttore e i costruttori non possono restituire nulla. Ma puoi evitarlo memorizzando il risultato nell'istanza e poi gettandolo da un operatore di cast a qualsiasi cosa tu voglia.

+0

... e non può restituire nulla. quindi devi memorizzare il risultato e aggiungere un operatore di cast. (Buona prova comunque.) – alfC

+0

@alfC Esattamente! Grazie. – peterh

4

Non riesco a vedere alcun motivo tecnico per vietare un static auto operator()(...). Ma è un caso speciale, quindi complicherebbe lo standard per aggiungere supporto. E tale complicazione non è necessaria, perché è molto facile da emulare:

struct L 
{ 
    static void func() {} 

    void operator()() const { func(); } 

    operator auto() const 
    { 
     return &L::func; 
    } 
}; 

Vedi Johannes' answer per un po ', eventualmente, informazioni utili in più.