在下面的代码中,有两个std::for_each使用boost:bind表达式的"等效"调用.指示的行编译,指示的失败行失败.我能在标准中找到的最佳解释相当于"因为我们这么说".我正在寻找"为什么标准表明这种行为".我的假设在下面.
我的问题很简单:为什么指示的行编译和等效的后续行无法编译(我不想因为"标准这样说",我已经知道 - 我不会接受任何给出这个的答案解释;我想解释标准为何如此说明.
注意:虽然我使用boost,但boost与此问题无关,并且使用g ++ 4.1.*和VC7.1重现了各种格式的错误.
#include <boost/bind.hpp>
#include <iostream>
#include <map>
#include <algorithm>
class Base
{
protected:
void foo(int i)
{ std::cout << "Base: " << i << std::endl; }
};
struct Derived : public Base
{
Derived()
{
data[0] = 5;
data[1] = 6;
data[2] = 7;
}
void test()
{
// Compiles
std::for_each(data.begin(), data.end(),
boost::bind(&Derived::foo, this,
boost::bind(&std::map<int, int>::value_type::second, _1)));
// Fails to compile - why?
std::for_each(data.begin(), data.end(),
boost::bind(&Base::foo, this,
boost::bind(&std::map<int, int>::value_type::second, _1)));
}
std::map<int, int> data;
};
int main(int, const char**)
{
Derived().test();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
指示的行因此错误而失败:main.C:在成员函数'void Derived :: test()'中:main.C:9:错误:'void Base :: foo(int)'受保护main.C:31 :错误:在此上下文中
如上所述,上面所谓的等效语句干净地编译(如果有问题的陈述被注释掉,则在预定的结果中运行"5","6","7"在不同的行上).
在寻找解释时,我在标准中遇到了11.5.1(具体来说,我正在查看2006-11-06草案):
当非静态数据成员或非静态成员函数是其命名类的受保护成员时,将应用超出第11节中所述之外的其他访问检查(11.2).105)如前所述,授予对受保护成员的访问权限,因为引用发生在朋友或某个类C的成员中.如果访问要形成指向成员的指针(5.3.1),则嵌套名称说明符应命名为C或从C派生的类.所有其他访问涉及(可能是隐含的)对象表达式(5.2.5).在这种情况下,对象表达式的类应为C或从C派生的类.
读完之后,第一个成功的第二个陈述失败的原因显而易见,但后来出现了问题:这个理由是什么?
我最初的想法是编译器正在扩展boost :: bind模板,发现Base :: foo受到保护并将其踢掉,因为boost :: bind <...>不是朋友.但是,我越是想到这个解释,它就越少有意义,因为如果我没记错的话,只要你把指针指向一个成员(假设你最初是在成员的访问控制范围内),所有的访问控制信息都是丢失(即我可以定义一个函数,该函数返回一个指向成员的任意指针,该成员根据某些输入交替返回公共成员,受保护成员或私有成员,并且返回者不会更聪明).
我想到了更多,并且我能想出的唯一合理的解释是什么它应该有所作为是在多重继承的情况下.具体来说,根据类布局,从Base计算的成员指针与从Derived计算的成员指针不同.
这都是关于"背景"的.在第一次调用中,调用的上下文Derived可以访问受保护的成员,Base因此可以获取它们的地址.在第二个中,上下文是"在...之外" Derived,因此在外部,Base因此不允许受保护的成员访问.
| 归档时间: |
|
| 查看次数: |
1802 次 |
| 最近记录: |