Es ist technisch undefined Verhalten, eine andere Sequenz von Token zu verwenden, um dieselbe Entität (hier eine Klasse) in verschiedenen Übersetzungseinheiten zu definieren.
Unabhängig von der Technik, die Sie verwenden, solange es die Reihenfolge der Token ändert, die es zusammensetzen, ist es vom Standard her übel (obwohl es in der Praxis wahrscheinlich funktioniert).
Johannes discovered a way dies unter Einhaltung der Norm zu tun. Es basiert auf der Tatsache, dass, obwohl a
ist ein privates Attribut in der Klasse A
, &A::a
kann in Kontexten geschrieben werden, die A.a
schreiben können (vielleicht ein Versehen im Standard?).
Core-Methode:
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;
}
Erweiterung für Einfachheit:
template<typename Tag, typename Member>
struct TagBase {
typedef Member type;
friend type get(Tag);
};
struct A_f : TagBase<A_f, int A::*> { };
EDIT:
Dieser Trick ist (witziger) explicitly allowed von der Standard-
§14.7.2/12 Die üblichen Zugriffskontrollregeln gelten nicht für Namen, die explizite Instanziierungen angeben. [...]
der Teufel verwendet: '#define privat public' – smerlin
schön:) ....... aber das wird jede Zeit –
@smerlin nicht: ich vermeiden würde. Aus einer juristischen Sicht ist dies in sich * undefiniertes Verhalten * weil 'private' ein reservierter Bezeichner ist (ein Compiler könnte einen Fehler erzeugen und sich weigern, die Anweisung zu kompilieren oder stillschweigend zu ignorieren). Zweitens hängt das Layout einer Klasse von der Zugriffsebene der Mitglieder ab. Obwohl es sich um ein selten verwendetes Feature handelt, könnten Sie subtile Fehler einführen, indem verschiedene Teile des Programms ein anderes Speicherlayout für das gleiche Objekt erwarten. –