Why does a hole for access checking exist for expl

2020-08-17 07:01发布

问题:

[temp.explicit] contains this wording:

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 ]

Why are those rules disabled specifically for this case? In the extreme, this allows for arbitrary access of any private member of any class in a well-defined way (demo - zero warnings):

struct A {
private:
  int member;
};

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

// tag used to access A::member
struct A_member { 
  typedef int A::*type;
  friend type get(A_member);
};

template struct Rob<A_member, &A::member>;

int main() {
  A a;
  a.*get(A_member()) = 42; // write 42 to it
  std::cout << "proof: " << a.*get(A_member()) << std::endl;
}

So that's the downside of this rule. What's the upside? Why do we need this hole to avoid access checking?

回答1:

This question is covered by Herb Sutter's GotW #76. Member functions are expected to be able to access private members of a class. When member function is a template, you would expect to be able to specialize such template. This is a conflict between the C++ access control model and the template model, which could be avoided by complicating (already complex) C++ standard. While it is possible to bypass C++ access controls and access private members in this way, you are strongly advised against doing that.

Note: @Xeo already explained most of these points in his comments above.