boost :: bind with protected members&上下文 [英] boost::bind with protected members & context

查看:119
本文介绍了boost :: bind with protected members&上下文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的代码中,有两个等价调用 std :: for_each 使用 boost:bind 表达式。指示的行编译,指示的失败线失败。我能在标准中找到的最好的解释是因为我们这样说。我在寻找为什么标准表明这种行为。我的假设如下。

In the below code, there are two "equivalent" calls to std::for_each using boost:bind expressions. The indicated line compiles, the indicated failing line fails. The best explanation I can find in the standard amounts to "because we said so". I'm looking for "why the standard indicates this behavior". My suppositions are below.

我的问题是:为什么指定的行编译和等效的下面的行无法编译(我不想因为标准所以,我已经知道了 - 我不会接受任何答案,作为解释;我想解释为什么标准这样说)。

My question is simply: Why does the indicated line compile and the equivalent following line fail to compile (and I don't want because "the standard says so", I already know that - I will not accept any answers that give this as an explanation; I'd like an explanation as to why the standard says so).

注意:虽然我使用boost,boost与这个问题无关,并且各种格式的错误已使用g ++ 4.1。*和VC7.1重现。

Notes: Although I use boost, boost is irrelevant to this question, and the error in various formats has been reproduced using g++ 4.1.* and 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;
}

指定的行失败并显示此错误:
main.C:在成员函数'void Derived :: test()':
main.C:9:error:'void Base :: foo(int)'被保护
main.C:31:error:within这个上下文

The indicated line fails with this error: main.C: In member function 'void Derived::test()': main.C:9: error: 'void Base::foo(int)' is protected main.C:31: error: within this context

如上所述,上面的等价语句完全编译(如果违规语句被注释掉,运行时打印5,6 ,7在不同的行)。

As noted, the supposedly equivalent statement above compiles cleanly (and if the offending statement is commented out, runs with the expected result of printing "5", "6", "7" on separate lines).

在搜索解释的时候,我发现了11.5.1标准(具体来说, -11-06草案):

While searching for an explanation, I came across 11.5.1 in the standard (specifically, I’m looking at the 2006-11-06 draft):


在第11条中描述的额外的访问检查
当非静态数据
成员或非静态成员函数是
a其命名类的受保护成员
(11.2)105)如前所述,
访问受保护成员是
授予,因为引用发生在朋友或某个类C的成员中的

如果访问是形成指向
成员(5.3.1)的指针,
嵌套名称说明符应该命名为C或
a从C派生的类。所有其他
访问涉及一个(可能是隐式)
对象表达式(5.2.5)。在这个
情况下,对象
表达式的类应该是C或者从C派生的类

An additional access check beyond those described earlier in clause 11 is applied when a non-static data member or nonstatic member function is a protected member of its naming class (11.2)105) As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C. If the access is to form a pointer to member (5.3.1), the nested-name-specifier shall name C or a class derived from C. All other accesses involve a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall be C or a class derived from C.

阅读完之后,很明显,为什么第二个语句在第一次成功时失败了,但是后来出现了问题:这是什么原因?

After reading this, it became evidently why the second statement failed while the first succeeded, but then the question came up: What is the rationale for this?

我最初的想法是,编译器扩展boost ::绑定模板,发现Base :: foo被保护,并踢它,因为boost :: bind< ...>不是一个朋友。但是,我对这个解释的想法越少,它的意义越少,因为如果我记得正确,只要你把指针指向一个成员(假设你最初在成员的访问控制),所有访问控制信息丢失(即,我可以定义一个函数,返回一个成员的任意指针,根据一些输入交替返回一个公共,受保护或私有成员,并且returner将是更聪明的)。

My initial thought was that the compiler was expanding the boost::bind templates, discovering that Base::foo was protected and kicking it out because boost::bind<…> was not a friend. But, the more I thought about this explanation, the less it made sense, because if I recall correctly, as soon as you take the pointer to a member (assuming you initially are within access control of the member), all access control information is lost (i.e. I could define a function that returns an arbitrary pointer to a member that alternately returns a public, protected or private member depending on some input and the returner would be none the wiser).

更多我想到了,唯一合理的解释我可以想出为什么它应该有所作为是多重继承的情况。具体来说,根据类布局,从Base计算时的成员指针将不同于从Derived计算的成员指针。

More I thought about it, and the only plausible explanation I could come up with why it should make a difference was in the case of multiple inheritance. Specifically, that depending on the class layout, the member pointer when calculated from Base would be different than that calculated from Derived.

推荐答案

这是所有关于上下文。在第一次调用中,调用的上下文是 Derived ,它可以访问 Base 的受保护成员,因此被允许采取他们的地址。在第二个上下文是之外 Derived ,因此在 Base 之外,所以不允许受保护的成员访问。

It's all about "context". In the first call the context of the call is Derived which has access to the protected members of Base and hence is allowed to take addresses of them. In the second the context is "outside of" Derived and hence outside of Base so the protected member access is not allowed.

这篇关于boost :: bind with protected members&amp;上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆