Mat*_* M. 13 c++ standards-compliance c++11
我们臭名昭着的litb有一篇关于如何规避访问检查的有趣文章.
这个简单的代码充分证明了这一点:
#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;
}
Run Code Online (Sandbox Code Playgroud)
其中编译和运行(输出42)与GCC 4.3.4,GCC 4.5.1,GCC 4.7.0(见user1131467的评论),并与锵3.0和科莫ç编译/ C++ 4.3.10.1在C++ 03严格的模式和2005年的MSVC .
Luchian向我询问了这个答案,我用它来证明它实际上是合法的.我同意Luchian的说法很奇怪,但是Clang和Comeau都是最常用的"标准"编译器的竞争者(默认情况下比MSVC更多)......
我在标准草案中找不到任何内容(n3337是我得到的最后一个版本).
那么......任何人都可以证明它是合法的吗?
GMa*_*ckG 13
是的,这是合法的.相关文本见§14.7.2/ 12,讨论了显式模板实例化:
12通常的访问检查规则不适用于用于指定显式实例化的名称.[ 注意:特别是,函数声明符中使用的模板参数和名称(包括参数类型,返回类型和异常规范)可能是通常不可访问的私有类型或对象,模板可能是成员模板或成员函数通常无法访问.- 结束说明 ]
Emhpasis我的.
代码显然是非法的(并且需要编译时诊断).在线:
template struct Rob<A_f, &A::a>;
Run Code Online (Sandbox Code Playgroud)
表达式A::a访问私有成员A.
标准非常明确:"访问控制统一应用于所有名称,无论名称是从声明还是表达式引用."(§11/ 4,重点补充).由于a是私人名称A,因此对它的任何引用A都是非法的.