来自博客文章 Access to private members: Safer nastiness由 Johannes Schaub - litb :
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;
}
如何get
函数可以从 a
调用对象,因为它没有在 class A
内部定义?
编辑:
我不明白为什么 get 必须有 Tag 作为参数而不是 a.*get<A_f>()
=> 好的,这是由于 ADL 机制
最佳答案
你不是从 a
调用 get
!实际上得到的返回是一个指向 A
内部成员的类指针,它的类型是 int A::*
所以你需要一个 A
的实例> 访问该值。
例如,让我玩一下你的代码:
struct A {
A(int a):a(a) { }
int b;
private:
int a;
};
void test() {
auto p = &A::b;
std::cout << a.*p << std::endl;
}
我是否从 a
内部调用了 p
? a
没有 p
,这正是你的代码中发生的情况,get
函数返回 &A::a
然后你使用 a
来读取它的值!就是这样,没有错,我认为它会在所有编译器中编译。
这里的另一个问题是:为什么 C++ 允许使用 A
的私有(private)成员声明模板。 C++ 标准说:
14.7.2p8 The usual access checking rules do not apply to names used to specify explicit instantiations. [Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects which would normally not be accessible and the template may be a member template or member function which would not normally be accessible.]
但是如果你尝试实例化甚至是 typedef
指定的模板那么你会得到一个错误。
让我们稍微修改一下您的示例:
struct A {
private:
int a;
friend void f();
};
// Explicit instantiation - OK, no access checks
template struct Rob<A_f, &A::a>;
// Try to use the type in some way - get an error.
struct Rob<A_f, &A::a> r; // error
typedef struct Rob<A_f, &A::a> R; // error
void g(struct Rob<A_f, &A::a>); // error
// However, it's Ok inside a friend function.
void f() {
Rob<A_f, &A::a> r; // OK
typedef Rob<A_f, &A::a> R; // OK
}
关于c++ - 使用模板技巧访问私有(private)成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12993219/