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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (48)

我碰巧发现可以使用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
提问于
用户回答回答于

Herb Sutter很久以前写过这篇文章,模板成员函数如何为课堂提供后门:http//www.gotw.ca/gotw/076.htm(请查看案例4:“语言律师” , 在末尾)

它可能会给你答案。

编辑:我很好奇,投票失败的原因是什么。我引用了这篇文章: “这是C ++访问控制机制中的一个漏洞,因此是C ++封装中的一个漏洞吗?这展示了两个C ++特性之间有趣的交互:访问控制模型和模板模型。事实证明,成员模板似乎隐含地“打破封装”,因为它们有效地提供了一种绕过类访问控制机制的可移植方式。“

似乎对我来说是一个合理的答案。 编辑结束

人们可以花费大量时间尝试通过技术手段保护接口私有/受保护等。我首选的方法是在所有开发人员之间达成协议,使用良好,理解符合最少惊喜方法的规则。(编辑:并定期使用code-reviews / reg-exp脚本验证代码是否符合这些规则)

“不要试图找到解决社会问题的技术方案”B. Stroustrup

用户回答回答于

这绝对是一个编译器错误,实际上已经知道了很长一段时间: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,因为这个特殊的错误似乎只发生在模板别名中。一个“解决方法”(如果你需要这样的东西,编译器允许错误的情况......)将恢复到预C ++ 11模板别名:

template <typename>
struct T {
    using type = A::B;
};

T<void>::type t;

该代码正确无法使用clang进行编译(错误:'B'是'A'的私有成员),但仍可使用gcc编译。

扫码关注云+社区

领取腾讯云代金券