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

标签 c++ templates gcc

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

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 ]

如果我可以实例化模板,我希望能够使用它。

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

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

#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;
}

如果您想知道这种可解雇的违规行为的用例是什么:创建一个框架,该框架将根据所选组件的实现选择自动配置应用程序。

最佳答案

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

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>;

如果没有这条规则,我将无法在命名空间范围内命名 Foo::Bar 甚至 Foo::Baz,因为这些名称对 Foo.

因为我实际上并没有使用 Foo::BarFoo::Baz 在这里,只是引用他们的名字来告诉编译器我在其他地方实例化模板,没有真正的访问冲突(尽管可以使用此规则执行非常 sneaky trick 否则不可能)。

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

关于c++ - 为什么通常的访问控制检查适用于通过模板参数访问时用于指定显式实例化的名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23920027/

相关文章:

c++ - 使用 visual stdio2008 的线程

c++ - 枚举类型的过度限定

c++ - 将字段名称传递到函数模板中

c - gcc 中有 128 位整数吗?

android - NDK 构建错误

c++ - (z-xi)^2 的最小化

c - 在 C 中编写方法时遇到问题,包括指针和类型

c++ - GCC 中的模板看不到在它之后声明的函数,而是在实例化之前

c++ - Qt 5 中的类声明和命名空间

c++ - 模板函数作为模板类的友元