C++ 为什么通常的访问控制检查适用于通过模板参数访问时用于指定显式实例化的名称?

C++ 为什么通常的访问控制检查适用于通过模板参数访问时用于指定显式实例化的名称?,c++,templates,gcc,C++,Templates,Gcc,C++11/14标准在注释14.7.2/12[temp.explicit]中说明了以下内容: 通常的访问检查规则不适用于用于指定 显式实例化。[注意:特别是模板参数 函数声明器中使用的名称(包括参数类型、, 返回类型和异常规格)可以是私有类型或对象 通常不可访问,模板可能是成员 通常无法访问的模板或成员函数。-结束注释] 如果我能实例化一个模板,我希望它能被允许使用 我尝试使用gcc-4.8.2,当我访问显式命名类的私有成员时,我得到了预期的行为。但是,当我通过模板参数访问私有成员时,访问检查规

C++11/14标准在注释14.7.2/12[temp.explicit]中说明了以下内容:

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

如果我能实例化一个模板,我希望它能被允许使用

我尝试使用gcc-4.8.2,当我访问显式命名类的私有成员时,我得到了预期的行为。但是,当我通过模板参数访问私有成员时,访问检查规则确实适用。这是gcc中的错误,还是我遗漏了什么

在下面的代码中,“成功”和“失败”之间的唯一区别是前者通过“A”直接访问私有成员,而后者通过模板参数“T”访问私有成员。编译器抱怨privateFoobar在该上下文中是私有的

#include <iostream>
#include <string>

struct A
{
private:
    std::string privateFoobar() {return "private foobar!";}
};

typedef std::string (A::*Foobar)();

template <class Type, Type value>
struct Access
{
    static Type getValue() {return value;}
};

template <class T>
struct IndirectAccess
{
    static Foobar succeeds() {return Access<Foobar, &A::privateFoobar>::getValue();}
    static Foobar fails() {return Access<Foobar, &T::privateFoobar>::getValue();}
};

template class Access<Foobar, &A::privateFoobar>;

int main() {
    std::cout << (A().*Access<Foobar,&A::privateFoobar>::getValue())() << std::endl;
    std::cout << (A().*IndirectAccess<A>::succeeds())() << std::endl;
    std::cout << (A().*IndirectAccess<A>::fails())() << std::endl;
}
#包括
#包括
结构A
{
私人:
std::string privateFoobar(){返回“privateFoobar!”;}
};
typedef std::string(A::*Foobar)();
模板
结构访问
{
静态类型getValue(){return value;}
};
模板
结构间接访问
{
静态Foobar成功(){return Access::getValue();}
静态Foobar失败(){return Access::getValue();}
};
模板类访问;
int main(){

std::cout显式实例化必须在命名空间范围内,这意味着类的私有成员通常无法访问。如果没有您引用的规则,这将是不可能的:

class Foo
{
private:
  struct Bar;

  template<typename T> class Baz { };

public:
  void f();  // does things with Baz<Bar>
};

// explicit instantiation declaration
extern template class Foo::Baz<Foo::Bar>;
class-Foo
{
私人:
结构杆;
模板类Baz{};
公众:
void f();//用Baz做事情
};
//显式实例化声明
外部模板类Foo::Baz;
如果没有这个规则,我将无法在命名空间范围内命名
Foo::Bar
甚至
Foo::Baz
,因为这些名称是
Foo
的私有名称

由于我实际上没有在这里使用
Foo::Bar
Foo::Baz
,只是引用它们的名称来告诉编译器我正在其他地方实例化模板,因此没有真正的访问冲突(尽管可以使用此规则执行非常不可能的其他操作)


类似地,当我在其他文件中编写显式实例化定义时,我需要能够在命名空间范围中再次引用私有名称。

您引用的标准引用是关于显式实例化的;您提供的程序不包含显式实例化。我提交的问题是,您不清楚显式实例化是什么实例化是。请看14.7.2/1到/4。@Casey很好,我添加了(在本例中没有意义)显式实例化并澄清了我的期望。问题更符合:如果我不能在代码中使用模板,为什么标准允许我显式实例化模板?我缺少什么?+1但为什么不链接到Johannes在这里对他的技巧的阐述,而不是Dave Abrahams的重写。当然会首先需要找到它。因为我不知道它是开着的,所以Google返回了它的要点。它在要点中有Johannes博客的URL,所以链接到这里,你就可以得到原稿和解释。我想这是Johannes第一次在SO上对它进行阐述。在那里,他还举例说明了成员函数指针转换中的反直觉类型系统漏洞n规则。