问题描述
来自博客文章 访问私人成员:更安全的肮脏 by 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;
}
如何从 a
对象调用 get
函数,因为它没有在 class A
中定义?
how get
function can be call from a
object since its not defined inside class A
?
我不明白为什么 get 必须有 Tag 作为参数而不是 a.*get()
=> 好的,这是由于 ADL 机制
I don't understand why get must have Tag as parameter instead of a.*get<A_f>()
=> ok it's due to ADL mechanism
推荐答案
你不是从 a
调用 get
!实际上返回的是一个指向 A
内部成员的类指针,它的类型是 int A::*
所以你需要一个 A
的实例> 访问该值.
You are not calling get
from a
! Actually what get return is a class pointer to a member inside A
and type of it is int A::*
so you need an instance of A
to access that value.
例如让我玩一下你的代码:
For example let me play a little with your code:
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
来读取它的值!就是这样,没有错,我认为它会在所有编译器中编译.
Did I call p
from inside a
? a
does not have p
, this is exactly what happened in your code, get
function return &A::a
and you use a
to read its value! that's all, nothing is wrong and I think it will be compiled in all compilers.
这里的另一个问题是:为什么 C++ 允许使用 A
的私有成员声明模板.C++ 标准说:
One other question here is: Why C++ allow declaring template using private member of A
. C++ standard say:
14.7.2p8 通常的访问检查规则不适用于用于指定显式实例化的名称.[注:特别是模板函数声明器中使用的参数和名称(包括参数类型、返回类型和异常规范)可能是通常无法访问的私有类型或对象模板可以是成员模板或成员函数通常无法访问.]
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
指定的模板,则会出现错误.让我们稍微修改一下您的示例:
But if you try to instantiate or even typedef
specified template then you get an error.
Let's modify your example slightly:
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
}
这篇关于使用模板技巧访问私人成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!