我碰巧发现可以使用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"
}
标记为“错误:__ 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
答案 0 :(得分:24)
这绝对是一个编译器错误,实际上已经知道了很长一段时间: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;
然而,Clang在这方面严格优于GCC,因为这个特殊的错误似乎只出现在模板别名中。 A&#34;解决方法&#34; (如果编译器允许错误的情况需要这样的事情......)将恢复到预C ++ 11模板别名:
template <typename>
struct T {
using type = A::B;
};
T<void>::type t;
该代码无法使用clang进行编译(错误:&#39; B&#39;是&#39; A&#39;的私有成员),但仍可使用gcc编译。
答案 1 :(得分:3)
Herb Sutter很久以前写过这篇文章,模板成员函数如何为类提供后门: http://www.gotw.ca/gotw/076.htm(请查看案例4:&#34;语言律师&#34;,最后)
它可能会给你答案。
编辑:我很好奇,投票失败的原因是什么。我引用这篇文章: &#34;这是C ++访问控制机制中的一个漏洞,因此是C ++封装中的漏洞吗? 这展示了两个C ++特性之间的有趣交互:访问控制模型和模板模型。事实证明,成员模板似乎隐含地打破了封装&#34;从某种意义上说,它们有效地提供了一种绕过类访问控制机制的便携方式。&#34;
对我来说似乎是一个合理的答案。 编辑结束
可以花费大量时间尝试通过技术手段保护接口私有/受保护等。我首选的方法是在所有开发人员之间达成协议,使用良好,理解符合最少惊喜方法的规则。 (编辑:并定期使用代码评论/ reg-exp脚本验证代码违反这些规则)
&#34;不要试图找到社会问题的技术解决方案&#34; B. Stroustrup