2012-03-28 12 views
13

Il nostro famigerato litb ha un interessante articolo su how to circumvent the access check.Il puntatore ai membri elude il livello di accesso di un membro?

E 'pienamente dimostrato da questo semplice codice:

#include <iostream> 

template<typename Tag, typename Tag::type M> 
struct Rob { 
    friend typename Tag::type get(Tag) { 
    return M; 
    } 
}; 

// use 
struct A { 
    A(int a):a(a) { } 
private: 
    int a; 
}; 

// tag used to access A::a 
struct A_f { 
    typedef int A::*type; 
    friend type get(A_f); 
}; 

template struct Rob<A_f, &A::a>; 

int main() { 
    A a(42); 
    std::cout << "proof: " << a.*get(A_f()) << std::endl; 
} 

che riunisce e piste (in uscita) con 42gcc 4.3.4, gcc 4.5.1, gcc 4.7.0 (vedi il commento di user1131467) e compila con Clang 3.0 e Comeau C/C++ 4.3.10.1 in C++ 03 rigorosa modalità e MSVC 2005.

mi è stato chiesto da Luchian su this answer in cui ho usato per giustificare il fatto che in realtà era legale. Sono d'accordo con Luchian che è strano, tuttavia sia Clang che Comeau sono contendenti per i compilatori più "Standard" disponibili (molto più di MSVC di default) ...

E non ho trovato nulla nelle bozze degli standard che ho a disposizione (n3337 è l'ultima versione su cui ho messo le mani).

Quindi ... qualcuno può effettivamente giustificare che sia legale o non?

+0

FYI Questo produce 'proof: 42' con' g ++ - 4.7 (Debian 4.7.0-1) 4.7.0' in entrambi '-std = C++ 11' e' -std = gnu ++ 11' –

+0

Scusa, questo è il mio cattivo. Questo è compilato, ciò che non è stato compilato era http://stackoverflow.com/a/6886432/673730 - e stavo cercando di accedere a una funzione privata, non a un membro dei dati. –

+0

Comunque sto ancora cercando una risposta, se la risposta ha funzionato, sarebbe stato esattamente quello che stavo cercando, ma non è così. –

risposta

13

Sì, è legale. Il testo in questione è a §14.7.2/12, si parla di esplicito modello di istanza:

12 Il solito regole di accesso di controllo non si applicano ai nomi utilizzati per specificare istanze esplicite. [Nota: In particolare, gli argomenti del modello e i nomi utilizzati nel dichiaratore di funzioni (inclusi tipi di parametri, tipi di ritorno e specifiche di eccezione) possono essere tipi o oggetti privati ​​che normalmente non sarebbero accessibili e il modello potrebbe essere un modello membro o funzione membro che normalmente non sarebbe accessibile. - end note]

Emhpasis mio.

+4

Ah! Questo è probabilmente ciò che mi piace di più dello Standard, per avere una visione completa di qualcosa, devi solo arrancare per tutto il pezzo e mettere insieme i pezzi. –

+1

@MatthieuM .: Ma è anche per questo che odio lo standard! :) EDIT: Whoosh! – GManNickG

+0

Questo doveva essere ironico;) Anche se ora è un on-line, forse potremmo proporre una modifica per rimandare questo paragrafo al James citato! –

5

Il codice è chiaramente illegale (e richiede una diagnostica in fase di compilazione). Nella linea:

template struct Rob<A_f, &A::a>; 

l'espressione A::a accede a un membro privato di A.

lo standard è molto chiaro su questo: Controllo “ accesso è applicata uniformemente a tutti nomi, se i nomi sono indicati da dichiarazioni o espressioni. “ (§11/4, corsivo aggiunto). Poiché a è un nome privato in A, qualsiasi riferimento ad esso esterno a A è illegale.

+3

In realtà non è illegale, un'eccezione viene aggiunta in seguito per le istanze dei modelli esplicite. Il "tutto" è ovviamente fuorviante, è "tutto, se non diversamente specificato". Non farò downvote perché non è intuitivo. – GManNickG

+0

@GManNickG In realtà, non è chiaro, e penso che un DR sia in ordine. Nello standard , "tutto" significa "tutto", non "tutto, se non diversamente specificato", e il contesto in §14.7.2 può consentire altre interpretazioni (sebbene esse siano non molto naturali). Sembra una contraddizione, il che significa che un DR è in ordine. –

+0

Hai ragione, non c'è bisogno che quella qualifica sia lì. – GManNickG

Problemi correlati