奇怪的编译器错误和模板继承

发布于 2024-09-17 12:16:21 字数 1625 浏览 9 评论 0原文

有人可以解释一下为什么这段代码:

class safe_bool_base
{ //13
    protected:

        typedef void (safe_bool_base::*bool_type)() const;

        void this_type_does_not_support_comparisons() const {} //18

        safe_bool_base() {}
        safe_bool_base(const safe_bool_base&) {}
        safe_bool_base& operator=(const safe_bool_base&) { return *this; }
        ~safe_bool_base() {}
};

template <typename T=void> class safe_bool : public safe_bool_base
{
    public:

        operator bool_type() const
        {
            return (static_cast<const T*>(this))->boolean_test() ? &safe_bool_base::this_type_does_not_support_comparisons : 0;
        }

    protected:

        ~safe_bool() {}
};

template <> class safe_bool<void> : public safe_bool_base
{
    public:

        operator bool_type() const
        {
            return (boolean_test() == true) ? &safe_bool_base::this_type_does_not_support_comparisons : 0; //46
        }

    protected:

        virtual bool boolean_test() const = 0;
        virtual ~safe_bool() {}
};

产生以下编译器错误吗?

c:\project\include\safe_bool.hpp(46) : error C2248: 'safe_bool_base::this_type_does_not_support_comparisons' : cannot access protected member declared in class 'safe_bool_base'
c:\project\include\safe_bool.hpp(18) : see declaration of 'safe_bool_base::this_type_does_not_support_comparisons'
c:\project\include\safe_bool.hpp(13) : see declaration of 'safe_bool_base'

由于两个 safe_bool 模板均派生自 safe_bool_base,我不明白为什么无法访问基类的受保护成员。

我错过了什么吗?

Could someone explain me why this code:

class safe_bool_base
{ //13
    protected:

        typedef void (safe_bool_base::*bool_type)() const;

        void this_type_does_not_support_comparisons() const {} //18

        safe_bool_base() {}
        safe_bool_base(const safe_bool_base&) {}
        safe_bool_base& operator=(const safe_bool_base&) { return *this; }
        ~safe_bool_base() {}
};

template <typename T=void> class safe_bool : public safe_bool_base
{
    public:

        operator bool_type() const
        {
            return (static_cast<const T*>(this))->boolean_test() ? &safe_bool_base::this_type_does_not_support_comparisons : 0;
        }

    protected:

        ~safe_bool() {}
};

template <> class safe_bool<void> : public safe_bool_base
{
    public:

        operator bool_type() const
        {
            return (boolean_test() == true) ? &safe_bool_base::this_type_does_not_support_comparisons : 0; //46
        }

    protected:

        virtual bool boolean_test() const = 0;
        virtual ~safe_bool() {}
};

Produces the following compiler error ?

c:\project\include\safe_bool.hpp(46) : error C2248: 'safe_bool_base::this_type_does_not_support_comparisons' : cannot access protected member declared in class 'safe_bool_base'
c:\project\include\safe_bool.hpp(18) : see declaration of 'safe_bool_base::this_type_does_not_support_comparisons'
c:\project\include\safe_bool.hpp(13) : see declaration of 'safe_bool_base'

Since both safe_bool templates derive from safe_bool_base, I don't understand why one can't access a protected member of the base class.

Am I missing something ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

木有鱼丸 2024-09-24 12:16:55

Chubsdad 的回答澄清了您的问题:为什么模板专业化会出现错误。

现在以下 C++ 标准规则

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

将解释为什么通用模板实例化不会抛出错误。即使您有私有访问说明符,它也不会抛出异常。

Chubsdad's answer clarifies your question of why there's an error for the template specialization.

Now the following C++ standard rule

14.7.2/11 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. — endnote]

would explain why the generic template instantiation wouldn't throw an error. It will not throw even if you have private access specifier.

骄兵必败 2024-09-24 12:16:48

我不认为这与模板有任何关系。您的示例代码可以简化为这样,但它仍然会给出等效的错误:

class A
{
    protected:
        typedef void (A::*type)() const;
        void foo() const {}
};


class B : public A
{
    public:
        operator type() const
        {
            return &A::foo;
        }
};

我相信问题是您无法将成员函数指针返回到公共接口中的受保护成员。编辑:不正确...

I don't think this is anything to do with templates. Your example code can be reduced to this, and it still gives the equivalent error:

class A
{
    protected:
        typedef void (A::*type)() const;
        void foo() const {}
};


class B : public A
{
    public:
        operator type() const
        {
            return &A::foo;
        }
};

I believe the issue is you can't return member-function pointers to protected members in the public interface. (Edit: not true...)

苏佲洛 2024-09-24 12:16:44

这可能会有所帮助(也可以在非模板情况下重现)

struct A{
protected:
    void f(){}
};

struct B : A{
    void g(){&A::f;}        // error, due to Standard rule quoted below
};

int main(){
}

VS 给出“'A::f':无法访问
在类中声明的受保护成员
'A'"

对于相同的代码,科莫给出

“ComeauTest.c”,第 7 行:错误:
受保护函数“A::f”(声明于
第 3 行)是
无法通过“A”指针或对象访问 void g(){&A::f;}
^

“ComeauTest.c”,第 7 行:警告:
表达式没有效果 void
g(){&A::f;}

这是实现预期意图的固定代码

struct A{
protected:
    void f(){}
};

struct B : A{
    void g(){&B::f;}        // works now
};

int main(){
}

那么,为什么第一个代码片段不起作用?

这是因为 C++ Standard03 中的以下规则

11.5/1-“当派生类的友元或成员函数引用时
受保护的非静态成员函数
或受保护的非静态数据成员
基类,适用访问检查
除了前面描述的那些之外
第 11.102 条)除非形成
指向成员的指针(5.3.1),
访问必须通过指针来进行,
的引用或对象
派生类本身(或任何类
从该类派生)(5.2.5)。 如果
该访问是形成一个指向
成员,嵌套名称说明符
应命名派生类(或任何
从该类派生的类)。

因此,更改运算符函数内的返回值,如下所示

return (boolean_test() == true) ? &safe_bool<void>::this_type_does_not_support_comparisons : 0; //46 

return (static_cast<const T*>(this))->boolean_test() ? &typename safe_bool<T>::this_type_does_not_support_comparisons : 0; 

编辑 2:请忽略我的解释。大卫是对的。这就是它的归结。

struct A{
protected:
    int x;
};

struct B : A{
    void f();
};

struct C : B{};

struct D: A{            // not from 'C'
};

void B::f(){
    x = 2;         // it's own 'A' subobjects 'x'. Well-formed

    B b;
    b.x = 2;       // access through B, well-formed

    C c;
    c.x = 2;       // access in 'B' using 'C' which is derived from 'B', well-formed.

    D d;
    d.x = 2;       // ill-formed. 'B' and 'D' unrelated even though 'A' is a common base
}

int main(){} 

This should probably help (reproducible in a non template situation also)

struct A{
protected:
    void f(){}
};

struct B : A{
    void g(){&A::f;}        // error, due to Standard rule quoted below
};

int main(){
}

VS gives "'A::f' : cannot access
protected member declared in class
'A'"

For the same code, Comeau gives

"ComeauTest.c", line 7: error:
protected function "A::f" (declared at
line 3) is
not accessible through a "A" pointer or object void g(){&A::f;}
^

"ComeauTest.c", line 7: warning:
expression has no effect void
g(){&A::f;}

Here is the fixed code which achieves the desired intentions

struct A{
protected:
    void f(){}
};

struct B : A{
    void g(){&B::f;}        // works now
};

int main(){
}

So, why does the first code snippet not work?

This is because of the following rule in the C++ Standard03

11.5/1- "When a friend or a member function of a derived class references
a protected nonstatic member function
or protected nonstatic data member of
a base class, an access check applies
in addition to those described earlier
in clause 11.102) Except when forming
a pointer to member (5.3.1), the
access must be through a pointer to,
reference to, or object of the
derived class itself (or any class
derived from that class) (5.2.5). If
the access is to form a pointer to
member, the nested-name-specifier
shall name the derived class (or any
class derived from that class).

So change the return within operator functions as follows

return (boolean_test() == true) ? &safe_bool<void>::this_type_does_not_support_comparisons : 0; //46 

return (static_cast<const T*>(this))->boolean_test() ? &typename safe_bool<T>::this_type_does_not_support_comparisons : 0; 

EDIT 2: Please ignore my explanations. David is right. Here is what it boils down to.

struct A{
protected:
    int x;
};

struct B : A{
    void f();
};

struct C : B{};

struct D: A{            // not from 'C'
};

void B::f(){
    x = 2;         // it's own 'A' subobjects 'x'. Well-formed

    B b;
    b.x = 2;       // access through B, well-formed

    C c;
    c.x = 2;       // access in 'B' using 'C' which is derived from 'B', well-formed.

    D d;
    d.x = 2;       // ill-formed. 'B' and 'D' unrelated even though 'A' is a common base
}

int main(){} 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文