C ++ 11:为什么私有成员模板可以在课外访问?

时间:2015-01-15 09:26:16

标签: c++ templates c++11 language-lawyer using

我碰巧发现可以使用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

2 个答案:

答案 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