不允许成员函数的非指针 typedef?

发布于 2024-12-05 03:45:55 字数 1302 浏览 0 评论 0 原文

在得到这个问题的答案后,我发现有两个typedef 函数指针的有效方法。

typedef void (Function) ();
typedef void (*PFunction) ();

void foo () {}

Function * p = foo;
PFunction  q = foo;

我现在更喜欢 Function * p 而不是 PFunction q 但显然这不适用于指向成员函数的指针。考虑这个人为的例子。

#include <iostream>

struct Base {
    typedef void (Base :: *Callback) ();
                        //^^^ remove this '*' and put it below (i.e. *cb)
    Callback cb;

    void go () {
        (this->*cb) ();
    }

    virtual void x () = 0;

    Base () {
        cb = &Base::x;
    }
};

struct D1 : public Base {
    void x () {
        std :: cout << "D1\n";
    }
};

struct D2 : public Base {
    void x () {
        std :: cout << "D2\n";
    }
};  

int main () {
    D1 d1;
    D2 d2;
    d1 .go ();
    d2 .go ();
}

但是,如果我将其更改为新的首选样式: typedef void (Base :: Callback) ()Callback * cb,我会在 处收到编译器错误代码>类型定义

成员“Callback”上的额外限定“Base::”

错误演示

为什么这是不允许的?这只是一个疏忽还是会导致问题?

After getting an answer to this question I discovered there are two valid ways to typedef a function pointer.

typedef void (Function) ();
typedef void (*PFunction) ();

void foo () {}

Function * p = foo;
PFunction  q = foo;

I now prefer Function * p to PFunction q but apparently this doesn't work for pointer-to-member functions. Consider this contrived example.

#include <iostream>

struct Base {
    typedef void (Base :: *Callback) ();
                        //^^^ remove this '*' and put it below (i.e. *cb)
    Callback cb;

    void go () {
        (this->*cb) ();
    }

    virtual void x () = 0;

    Base () {
        cb = &Base::x;
    }
};

struct D1 : public Base {
    void x () {
        std :: cout << "D1\n";
    }
};

struct D2 : public Base {
    void x () {
        std :: cout << "D2\n";
    }
};  

int main () {
    D1 d1;
    D2 d2;
    d1 .go ();
    d2 .go ();
}

But if I change it to the new preferred style: typedef void (Base :: Callback) () and Callback * cb, I get a compiler error at the point of typedef

extra qualification 'Base::' on member 'Callback'

Demo for error.

Why is this not allowed? Is it simply an oversight or would it cause problems?

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

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

发布评论

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

评论(3

瑶笙 2024-12-12 03:45:55

对于非成员函数,诸如 typedef void(Function)() 之类的类型有多种用途,但对于成员函数,唯一的应用是声明一个保存函数指针的变量。因此,除了风格偏好之外,没有严格需要允许这种语法,并且它已从标准中省略。

背景

:: 是范围解析运算符,语法 X::Y 保留用于 static 成员访问,如果 X< /code> 是一个类类型。因此,X::*Z 是另一种为定义指向成员的指针而发明的语法。

暂时忘记成员函数,只考虑成员数据,看看这段代码:

struct X
{
   int a;
};

int X::*pa = &X::a; //pointer-to-member
X x = {100}; //a = 100
cout << (x.*pa) << endl;

它定义了指向成员数据的指针 >,并且 cout 使用它来打印对象 xa 的值,并打印:

100

Demo : http://www.ideone.com/De2H1

现在想想,如果 X::pa (而不是 X::*pa) 被允许这样做,那么您将上面的内容编写为:

int X::pa = X::a; //not &X::a

看到这个语法,您如何判断 X::a 是否是 static 成员或非静态成员?这就是标准提出指向成员的指针语法的原因之一,并将其​​统一应用于非静态成员数据以及非静态成员函数。

事实上,您不能编写X::a,您必须编写&X::a。语法 X::a 会导致编译错误(请参阅)。


现在将成员数据的这个参数扩展到成员函数。假设您的 typedef 定义为:

typedef void fun();

那么您认为以下代码会做什么?

struct X
{
   fun a;
};

好吧,它定义了 fun 类型的成员 a(这是不带参数、返回 void 的函数),并且等价于:

struct X
{
   void a();
};

惊讶吗?请继续阅读。

struct X
{
   fun a; //equivalent to this: void a();
};

void X::a() //yes, you can do this!
{
     cout << "haha" << endl;
}

我们可以使用完全相同的语法来引用现在是成员函数的 a

X x;
x.a(); //normal function call

void (X::*pa)() = &X::a; //pointer-to-member
(x.*pa)(); //using pointer-to-member

相似之处在于右侧的语法:&X::a 。无论a是指成员函数还是成员数据,语法都是相同的。

演示: http://www.ideone.com/Y80Mf

结论:

作为我们知道,无论a是成员数据还是成员函数,我们都不能在RHS上编写X::a。唯一允许的语法是 &X::f ,这使得目标类型(LHS 上)也必须是 pointer ,这反过来又使得语法 void (X::*pa)() 绝对必要且基本,因为它与该语言中的其他语法相匹配。

For non-member functions, a type such as typedef void(Function)() has several uses, but for member functions the only application is to declare a variable which holds a function pointer. Hence, other than a stylistic preference, there's no strict need to allow this syntax and it has been omitted from the standard.

Background

The :: is a scope resolution operator, and the syntax X::Y is reserved for static member access if X is a class type. So X::*Z was another syntax invented to define pointer-to-member.

Forget member-function for a while, just think about member-data, and see this code:

struct X
{
   int a;
};

int X::*pa = &X::a; //pointer-to-member
X x = {100}; //a = 100
cout << (x.*pa) << endl;

It defines a pointer-to-member-data, and the cout uses it to print the value of a of object x, and it prints:

100

Demo : http://www.ideone.com/De2H1

Now think, if X::pa (as opposed to X::*pa) were allowed to do that, then you've written the above as:

int X::pa = X::a; //not &X::a

Seeing this syntax, how would you tell if X::a is a static member or non-static member? That is one reason why the Standard came up with pointer-to-member syntax, and uniformly applies it to non-static member-data as well as non-static member-function.

In fact, you cannot write X::a, you've to write &X::a. The syntax X::a would result in compilation error (see this).


Now extend this argument of member-data to member-function. Suppose you've a typedef defined as:

typedef void fun();

then what do you think the following code does?

struct X
{
   fun a;
};

Well, it defines member a of type fun (which is function taking no argument, and returning void), and is equivalent to this:

struct X
{
   void a();
};

Surprised? Read on.

struct X
{
   fun a; //equivalent to this: void a();
};

void X::a() //yes, you can do this!
{
     cout << "haha" << endl;
}

We can use exactly the same syntax to refer to a which is now a member-function:

X x;
x.a(); //normal function call

void (X::*pa)() = &X::a; //pointer-to-member
(x.*pa)(); //using pointer-to-member

The similarity is the synatax on the right hand side : &X::a. Whether a refers to a member-function or member-data, the syntax is same.

Demo : http://www.ideone.com/Y80Mf

Conclusion:

As we know that we cannot write X::a on the RHS, no matter if a is a member-data or member-function. The only syntax which is allowed is &X::f which makes it necessary that the target type (on LHS) must be pointer as well, which in turn makes the syntax void (X::*pa)() absolutely necessary and fundamental, as it fits in with other syntax in the language.

胡大本事 2024-12-12 03:45:55

准确地说,在非成员指针的情况下,两个 typedef 是不同的:

typedef void function();
typedef void (*fptr)();

第一个将 function 定义为不带参数并返回 void函数,而第二个将 ftpr 定义为指向不带参数并返回 void 的函数的指针。由于函数类型在许多上下文中将隐式转换为指针类型,因此可能会出现混乱。但并非全部:

function f;            // declares void f();
struct test {
   function f;         // declares void test::f()
};
void g( function f );  // declares g( void (*f)() ): function decays to pointer to function in declaration
g( f );                // calls g( &f ): function decays to pointer to function
void f() {}            // definition of f
// function h = f;     // error: cannot assign functions
function *h = f;       // f decays to &f

To be precise the two typedef's in the case of the non-member pointers are not the same:

typedef void function();
typedef void (*fptr)();

The first defines function as a function taking no arguments and returning void, while the second defines ftpr as a pointer to function taking no arguments and returning void. The confusion probably arises as the function type will be implicitly converted to a pointer type in many contexts. But not all:

function f;            // declares void f();
struct test {
   function f;         // declares void test::f()
};
void g( function f );  // declares g( void (*f)() ): function decays to pointer to function in declaration
g( f );                // calls g( &f ): function decays to pointer to function
void f() {}            // definition of f
// function h = f;     // error: cannot assign functions
function *h = f;       // f decays to &f
秋风の叶未落 2024-12-12 03:45:55

让我们暂时跳过“函数”部分。在 C++ 中,我们有 intint*int Foo::* 类型。这是一个常规整数、指向整数的指针和指向整数成员的指针。不存在第四种“整数成员”。

这同样适用于函数:尽管有函数类型、函数指针类型和成员函数指针类型,但只是没有“成员函数”类型。

Let's skip the "function" part for a second. In C++, we have the int, the int* and the int Foo::* types. That's a regular integer, pointer to integer, and a pointer to an integer member. There is no fourth type "integer member".

Exactly the same applies to functions: there's just no type "member function", even though there are function types, function pointer types, and member function pointer types.

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