【问题标题】:Access control in template parameters模板参数中的访问控制
【发布时间】:2019-02-27 15:56:38
【问题描述】:

this answer这个号称颠覆门禁系统的启发,我写了下面这个最小版的hack

template<typename T>
inline T memptr{};

template<auto Val>
struct setptr
{
    struct setter { setter() { memptr<decltype(Val)> = Val; } };
    static setter s;
};

template<auto Val>
typename setptr<Val>::setter setptr<Val>::s{};

然后是used as

class S
{
    int i;
};

template struct setptr<&S::i>;

auto no_privacy(S& s)
{
    return s.*memptr<int S::*>;
}

为什么template struct setptr&lt;&amp;S::i&gt;; 没有违反访问控制?

是不是因为[class.access]

访问控制统一应用于所有名称,无论名称是从声明还是表达式引用。

具体不包括实例化?在这种情况下,为什么不包括实例化?

勘误表:显式实例化也被归类为声明。

【问题讨论】:

  • 我们实际上在代码库中的一个位置使用了这个“hack”,以便能够调用我们真正需要的库中的私有成员函数/i> call ;-) 但是,我怀疑它在测试框架中也很有用,您可能希望测试受保护的和私有的成员,而不必注入朋友和其他东西。
  • 如果您点击答案中的几个链接,您将到达this 评论版本,其中详细说明了显式实例化是您可以在忽略访问的情况下形成成员函数/字段指针的唯一地方.在 cmets 中链接的 this 库中有更多解释,以回答您链接的问题。
  • @MaxLanghof 我确实看到了这些,但找不到他们声称的来源。
  • 我们过去常常通过访问底层 FILE 句柄来解决旧版 Visual Studio 中存在错误的 std::fstream 实现

标签: c++ language-lawyer


【解决方案1】:

来自[temp.spec]/6(强调我的):

通常的访问检查规则不适用于显式实例化或显式特化声明中的名称,但出现在函数体、默认参数、基子句、成员中的名称除外- 规范、枚举器列表或静态数据成员或变量模板初始值设定项。 [ 注意:特别是,函数声明器中使用的模板参数和名称(包括参数类型、返回类型和异常规范)可能是通常无法访问的私有类型或对象。 —— 尾注 ]

所以你看到的这种技术滥用了这条规则,主要是为了允许类的实现者专门化具有私有类型或其他私有实体的模板(例如特征)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-18
    • 1970-01-01
    相关资源
    最近更新 更多