問題描述
來自博客文章 訪問私人成員:更安全的骯臟 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
}
這篇關于使用模板技巧訪問私人成員的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!