2011-09-09 13 views
5

Sarà possibile e/o utile definire una funzione operator "" (...) come amico?C++ 0x, valori letterali definiti dall'utente con operatore amico ""()

class Puzzle { 
    friend Puzzle operator "" _puzzle(const char*, size_t); 
    ... 
}; 
void solve(Puzzle); 
int main() { 
    solve("oxo,xox"_puzzle); 
}; 

Sto pensando di "utile" in particolare, a causa della regola che operator "" sono definite in un namespace solo - non ultimo perché identificatori che iniziano con _ sono riservati nel namespace globale. È questo friend infrangere questa regola qui? Quindi, non ci sarebbe alcun beneficio con questo incapsulamento non proprio, giusto?

risposta

2

Gli indirizzi standard questo direttamente nell'unico posto menziona restrizioni delle dichiarazioni di letterali definiti dall'utente, §13.5.8/2:

Una dichiarazione cui declarator-ID è un letterale operatore -id deve essere una dichiarazione di una funzione o di un modello di funzione dello scope dei nomi (potrebbe essere una funzione amico (11.3)), un'istanza esplicativa o specializzazione di un modello di funzione o una dichiarazione di utilizzo (7.3.3).

Se anche l'amico viene dichiarato nello scope dello spazio dei nomi, non vi è alcuna distinzione tra definizione in classe o ambito spazio dei nomi. Si noti che non vi è alcun obbligo per la definizione nello scope namespace, che la tua domanda come attualmente asserisce affermata.

Se non dichiarato nello spazio dei nomi, poiché non può essere trovato da ADL, l'amico può essere utilizzato privatamente all'interno della classe in cui è ambito dalla normale ricerca di nome non qualificato. Questo è l'unico modo per dichiarare un operatore letterale che non è un'interfaccia esterna.

Se l'amico è definito all'interno di un modello di classe, due istanze del modello genereranno due funzioni con nomi identici nello scope dello spazio dei nomi, che entrano in collisione anche se sono entrambe invisibili al di fuori dell'ambito della classe.

+0

Ho davvero pensato di averlo letto da qualche parte, che i suffissi * dovrebbero * essere dichiarati solo all'interno di uno ** spazio dei nomi **. Non riesco a ricordare dove - ma era solo un suggerimento, non un requisito. E quindi, probabilmente era l'unico consiglio per "buone pratiche". Buon punto a proposito della funzione ** template ** friend. Questo non è un problema con il solito schema * friend *, quello che almeno uno degli argomenti della funzione friend è un'istanza di classe stessa - quindi non c'è alcun problema di denominazione. – towi

+1

Ricordo di aver visto qualcosa di simile nei documenti di posizione precedenti. Prova n2378.pdf sezione 5: An Idiom. Qui dicono: 1. Queste funzioni non vengono trovate tramite ADL quando vengono richiamate tramite valori letterali invece di forma operatore esplicita. 2. Questo potrebbe tentare il posizionamento in globale. 3. Ciò porterebbe a conflitti anche nel codice che non usa il letterale. 4. Quindi metti le operazioni letterali in un namespace e metti una direttiva using per portarle a livello globale. – emsr

+0

Volevo solo notare che non è possibile * non * usare la funzione friend in privato all'interno della classe, vedere [questa domanda] (http://stackoverflow.com/questions/8207633/whats-the-scope-of-inline-friend -Funzioni). – Xeo

0

Secondo lo standard, sì, una dichiarazione di amicizia dovrebbe essere legale. A proposito, il nome va bene per il codice utente poiché inizia con un trattino basso anche nello spazio dei nomi globale.

La dichiarazione di amicizia consente all'operatore di accedere ai dati privati ​​della classe.

Sto iniziando a mettere in discussione l'utilità degli operatori letterali di amici. Poiché gli operatori definiti dall'utente possono avere solo pochi elenchi di argomenti, non c'è modo di inserire la classe negli argomenti. Quindi ora c'è modo per la ricerca dipendente da argomenti per trovare la funzione giusta. Ho ragione?

+0

Penso che ADL possa essere utilizzato, ma deve cercare un argomento 'const char *' o qualsiasi sia l'operatore per cui è stato definito. Comunque, dubito anche dell'utilità: Ok, puoi accedere ai dati privati, ma devi comunque chiamare un costruttore. BTW: johannes (altri commenti di anwers) ha sottolineato che il nome non è '_puzzle', ma' operator "" _puzzle' e quindi non dovrebbe iniziare con un underscore. – towi

+0

Sì, secondo 13.5.La ricerca regolare 8/7 prevarrà per gli operatori letterali. Ho il problema del nome. Sono stato bloccato su 17.6.4.3.5 che riserva suffissi letterali * senza * un punto di sottolineatura principale per l'implementazione. – emsr

+1

Penso che la cosa principale per cui sono stati progettati sia che avrebbero permesso un'implementazione solo su una libreria, diciamo, decimale. Gli operatori letterali definiti dall'utente offrono un gancio nel lexer. – emsr

1

Nel caso si aiuta con la sintassi, ecco come lo dichiaro un amico operatore letterale definito dall'utente in una classe, dove l'operatore stesso è in uno spazio dei nomi:

class Integer; 
namespace literals { 
    Integer operator "" _I (const char *); 
} 

// Infinite precision integer 
class Integer { 
    public: 

    // Basic constructor & destructor 
    Integer(); 
    ~Integer(); 

... rest of the interface ... 

    // Literal operator 
    friend Integer literals::operator "" _I (const char *); 

    private: 

    struct Detail; 
    std::unique_ptr<Detail> detail; 

}; 

Utenti tirare nell'operatore con un using namespace literals; solo se lo vogliono. (E, in realtà, tutto questo è in uno spazio dei nomi genitore, ma tu hai l'idea).

Problemi correlati