使用模板技巧访问私有成员

Gui*_*e07 17 c++ templates

从一个博客帖子访问私有成员:更安全的污秽约翰内斯·绍布- litb:

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

// use
struct A {
  A(int a):a(a) { }
private:
  int a;
};

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

template struct Rob<A_f, &A::a>;

int main() {
  A a(42);
  std::cout << "proof: " << a.*get(A_f()) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

如何geta对象调用函数,因为它没有在里面定义class A

编辑:

我不明白为什么get必须有Tag作为参数而不是 a.*get<A_f>() => ok它是由于ADL机制

Big*_*oss 7

你不打电话geta!实际上,返回的是一个指向内部成员的类指针A,它的类型是int A::*你需要一个A访问该值的实例.

例如,让我玩你的代码:

struct A {
    A(int a):a(a) { }
    int b;
private:
    int a;
};
void test() {
    auto p = &A::b;
    std::cout << a.*p << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我是p从里面打来的a吗?a没有p,这正是你的代码中发生的事情,get函数返回&A::a,你用它a来读取它的值!这就是全部,没有什么是错的,我认为它将在所有编译器中编译.

另一个问题是:为什么C++允许使用私有成员声明模板A.C++标准说:

14.7.2p8通常的访问检查规则不适用于用于指定显式实例化的名称.[注意:特别是,函数声明符中使用的模板参数和名称(包括参数类型,返回类型和异常规范)可能是通常不可访问的私有类型或对象,模板可能是成员模板或成员函数通常无法访问.]

但是,如果您尝试实例化甚至typedef指定模板,则会出现错误.让我们稍微修改你的例子:

struct A {
private:
    int a;
    friend void f();
};

// Explicit instantiation - OK, no access checks
template struct Rob<A_f, &A::a>;

// Try to use the type in some way - get an error.
struct Rob<A_f, &A::a> r;            // error
typedef struct Rob<A_f, &A::a> R;    // error
void g(struct Rob<A_f, &A::a>);      // error

// However, it's Ok inside a friend function.
void f() {
    Rob<A_f, &A::a> r;               // OK
    typedef Rob<A_f, &A::a> R;       // OK
}
Run Code Online (Sandbox Code Playgroud)

  • 这就是我喜欢C++的原因 (3认同)