How to read so many stars and parentheses in a templated function-pointer declaration? [duplicate]

左心房为你撑大大i 提交于 2019-11-28 21:37:46

In complement with @Vittorio answer, there is the Clockwise Spiral Rule to help us decypher complex types:

Starting with the unknown element, move in a spiral/clockwise direction; when encountering the following elements replace them with the corresponding English statements:

  • [X] or []

    Array X size of... or Array undefined size of...

  • (type1, type2)

    Function passing type1 and type2 returning...

  • *

    pointer(s) to...

Keep doing this in a spiral/clockwise direction until all tokens have been covered. Always resolve anything in parenthesis first!


Here:

           +-----------+
           | +------+  |
           | | >-v  |  |
temp<int> (*(*foo())())()
        |  | ^---+  |  |
        |  ^--------+  |
        +--------------+

foo is a function returning a pointer to a function returning a pointer to a function returning a temp<int>.


And now, @UKmonkey just renamed this rule The C++ Guru Snail Rule or CGSR for short:

 / /
 L_L_
/    \
|00  |       _______
|_/  |      /  ___  \
|    |     /  /   \  \
|    |_____\  \_  /  /
 \          \____/  /_____
  \ _______________/______\.............................

Where should I look at in the beginning?

Honestly, you should just look at https://cdecl.org/, which describes int (*(*foo())())(); as:

declare foo as function returning pointer to function returning pointer to function returning int

And then realize that this is C++11, and we have a really nice syntax for declaring function pointer aliases:

using A = int(*)(); // pointer to function returning int
using B = A(*)();  // pointer to function returning pointer to function returning int

B foo(); // function returning pointer to function returning pointer to function returning int

There's really no reason to write declarations like that today.

cdecl is an useful online tool to demystify complicated C declarations.

Inserting int (*(*foo())())() returns:

declare foo as function returning pointer to function returning pointer to function returning int

I've replaced tmp<int> with int as the tool does not support templates.

Correctly formatting the code may help you comprehend:

template <class T>
class tmp {
    public:
    int i;
};

auto foo() -> auto(*)() -> tmp<int>(*)() {
    return 0;
}
template <class T>
class tmp{
    public:
    int i;
};

tmp<int> (*
    ( *foo() )()
    )() {
    return 0;
}

The template class part remains the same so I'm not going to elaborate on it. Let's see the function foo.

In the first code, the return value of foo() is auto(*)() -> tmp<int>(*)(), which is a pointer to a function returning another pointer, which points to a function returning tmp<int>.

As you can always define a function pointer like:

base_type_t (*pointer_name)(parameter_list);

Recursing the pointer_name with a function (i.e. func_name()) can declare a function whose return value is such a pointer:

base_type_t (*func_name())(parameter_list);
              ~~~~~~~~~~~

So now (*func_name())(parameter_list) can serve another function. Let's put it back into the function pointer definition syntax:

base_type_t (*(*func_name())(parameter_list))(parameter_list);
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Clear the parameter list (they're empty) and replace the identifiers with the correct types gives:

base_type_t (*(*func_name())(parameter_list))(parameter_list);
tmp<int>    (*(*   foo   ())( /* Empty */  ))( /* Empty */  );

// Turns to
tmp<int> (*(*foo())())();

As others have already suggested, https://cdecl.org/ is a good code analyzer, though it may give you another sentence which is not quite easy to understand.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!