为什么此代码允许访问私有变量

Why this code allows accessing private variables

几天前我遇到了这种方法(作为 C++ course 中编程任务的解决方案之一)。

#include <iostream>

struct C {
    C(int i) { m_i = i; }
private:
    int m_i;
};

template<typename Tag, int C::* M>
struct Rob {
    friend
    int C::* get(Tag) {
        return M;
    }
};

template<typename D>
struct AcessorTag {
    typedef D C::*type;
};

template struct Rob<AcessorTag<int>, &C::m_i>;

int &get_c(C &cls) {
    return cls.*get(AcessorTag<int>());
}

int main()
{
    C c(13);
    std::cout << get_c(c);
    return 0;
}

你能解释一下为什么这段代码可以编译吗?这里发生的几乎所有事情都是 1) 我们将指向成员的指针作为参数传递给结构模板 2) 我们声明一个友元函数,它只是 returns 那个指向成员的指针。

这是标准的 C++ 吗? (我在 VS 2015 上测试过)

get 函数是 struct Rob<> 的友元,但不是 struct C 的友元。无论如何,struct C 似乎没有朋友,所以它的私有成员怎么可以访问?

谢谢!

当然,你的代码不能用gnu c++和clang++编译;标识符 get 不是 C 的成员。即使您尝试实例化 Rob,例如

Rob<AcessorTag<int>, &C::m_i> rob;

你获得了

error: 'int C::m_i' is private.

您可以随时询问 Microsoft 他们的 c++ 编译器是否符合任何标准。如果他们回答了,请告诉我他们的答案。

除了缺少 get 函数的前向声明之外,这段代码应该可以正常工作并且符合标准。由于适用于模板的显式实例化定义的特殊规则,此代码有效:

17.8.2 Explicit instantiation [temp.explicit]

14 The usual access checking rules do not apply to names used to specify explicit instantiations. [Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects which would normally not be accessible and the template may be a member template or member function which would not normally be accessible. —end note ]

所以写

template struct Rob<AcessorTag<int>, &C::m_i>;

将绕过通常的访问检查并使指向其他不可访问成员的指针可供 get 函数体使用。

this answer.

中很好地描述了制定这种奇特规则的动机