首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用模板技巧访问私有成员

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

Stack Overflow用户
提问于 2012-10-21 06:21:39
回答 3查看 4K关注 0票数 18

来自Johannes Schaub - litb的一篇博客文章

代码语言:javascript
复制
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;
}

既然get函数没有在class A中定义,那么如何从a对象调用它呢?

编辑:

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-10-21 07:50:49

您不能从a调用get!实际上,get返回的是一个指向A内部成员的类指针,它的类型是int A::*,所以你需要一个A的实例来访问这个值。

举个例子,让我用一下你的代码:

代码语言:javascript
复制
struct A {
    A(int a):a(a) { }
    int b;
private:
    int a;
};
void test() {
    auto p = &A::b;
    std::cout << a.*p << std::endl;
}

我是从a内部调用p的吗?a没有p,这正是您的代码中发生的事情,get函数返回&A::a,而您使用a读取它的值!仅此而已,没有任何错误,我认为它将在所有编译器中编译。

这里还有一个问题:为什么C++允许使用A的私有成员声明模板。C++标准说:

14.7.2p8通常的访问检查规则不适用于用于指定显式实例化的名称。注意:具体地说,函数声明符中使用的模板参数和名称(包括参数类型、返回类型和异常规范)可以是私有类型或对象,它们通常是不可访问的,并且模板可以是通常不可访问的成员模板或成员函数。

但是如果你试图实例化或者甚至是typedef指定的模板,那么你就会得到一个错误。让我们稍微修改一下您的示例:

代码语言:javascript
复制
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
}
票数 8
EN

Stack Overflow用户

发布于 2012-10-21 06:40:51

这是合法的,因为朋友函数总是在全局作用域中,即使你在一个类中实现它们。换句话说,这就是:

代码语言:javascript
复制
class A
{
    friend void go() {}
};

只是一个快捷方式:

代码语言:javascript
复制
class A
{
    friend void go();
};

void go() {}
票数 1
EN

Stack Overflow用户

发布于 2012-10-21 12:08:34

这是gcc中的一个已知编译器错误,已在以后的版本中修复。请参见-:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41437

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12993219

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档