nav*_*nav 33 c++ templates using language-lawyer c++11
我碰巧发现可以使用using指令直接在封闭类之外访问嵌套的私有模板类:
class wrapper
{
private:
template <typename T>
class __tklass {};
class __klass {};
};
template <typename T>
using tklass = wrapper::__tklass<T>; // Expected error but compiles OK
// using klass = wrapper::__klass; // "Error: __klass is private"
int main()
{
tklass<int> v1; // Expected error but compiles OK
// wrapper::__tklass<int> v3; // "Error: __tklass is private"
// wrapper::__klass v4; // "Error: __klass is private"
}
Run Code Online (Sandbox Code Playgroud)
标记为"错误:__ xxxx为私有"的行在取消注释时正确报告错误.但是tklass编译的行没有编译器的任何抱怨.
那么,为什么编译器标记tklass为错误,尽管wrapper::__tklass它是私有的?是否有标准允许的任何机会?如果是这样,那不会被认为是严重的访问违规行为吗?
我试过gcc-4.9.2,clang-3.5.0和visual studio 2013 express.GCC命令行:
g++ -std=c++11 -pedantic -Wall -Wextra -Wshadow myfile.cpp
Run Code Online (Sandbox Code Playgroud)
Bar*_*rry 26
这绝对是一个编译器错误,实际上已经知道了很长一段时间:GCC#47346(2011年1月首次报道)和Clang#15914(2013年5月首次报道).你__tklass显然private,和模板别名没有标记friend,所以这应该是一个简单的访问错误.
最简单的再现来自Clang示例附件,此版本在gcc 4.9.2和clang 3.5.0上编译,但绝对不应该编译:
class A
{
class B {};
};
template<typename>
using T = A::B;
T<void> t;
Run Code Online (Sandbox Code Playgroud)
但是,Clang在这方面严格优于GCC,因为这个特殊的bug似乎只出现在模板别名中.一个"解决方法"(如果你需要这样的东西,编译器允许错误的情况......)将恢复到预C++ 11模板别名:
template <typename>
struct T {
using type = A::B;
};
T<void>::type t;
Run Code Online (Sandbox Code Playgroud)
该代码正确无法使用clang进行编译(错误:'B'是'A'的私有成员),但仍可使用gcc编译.
Herb Sutter 很早之前写过一篇文章,模板成员函数如何为类提供后门: http://www.gotw.ca/gotw/076.htm(请检查案例 4:“语言律师” , 在最后)
它可能会给你答案。
编辑:我很好奇,拒绝投票的原因是什么。我引用了这篇文章: “这是 C++ 访问控制机制中的一个漏洞,因此也是 C++ 封装中的一个漏洞吗?这演示了两个 C++ 功能之间有趣的交互:访问控制模型和模板模型。事实证明,成员模板似乎隐含地“破坏封装”,因为它们有效地提供了一种绕过类访问控制机制的可移植方法。”
在我看来这是一个合理的答案。 编辑结束
人们可能会花费大量时间尝试通过私有/受保护等技术手段来保护接口。我的首选方法是在所有开发人员之间达成协议,使用符合最少意外方法的良好且易于理解的规则。(编辑:并定期使用 code-reviews/reg-exp 脚本根据这些规则验证代码)
“不要试图寻找社会问题的技术解决方案”B. Stroustrup
| 归档时间: |
|
| 查看次数: |
1475 次 |
| 最近记录: |