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;
}
如果您想知道这种可被解雇的罪行的用例是什么:创建一个框架,该框架将根据所选组件的实现选择自动配置应用程序。
显式实例化必须在命名空间范围内,这意味着类的私有成员通常无法访问。如果没有您引用的规则,这是不可能的:
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
.
因为我其实不是using Foo::Bar
or Foo::Baz
在这里,只是引用它们的名称来告诉编译器我正在其他地方实例化模板,不存在真正的访问冲突(尽管可以使用此规则来执行非常鬼鬼祟祟的把戏 https://gist.github.com/dabrahams/1528856否则不可能)。
同样,当我在其他文件中编写显式实例化定义时,我需要能够在命名空间范围内再次引用私有名称。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)