Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

From Introduction to the C++11 feature: trailing return types

The article claims

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

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

is equivalent to

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

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

I don't understand the complex function in the second code example. Where should I look at in the beginning? I guess is foo. But the stat right next to foo is going to define foo as a pointer... Based on the first code example, I will convert the piece as

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

So foo is a function, which returns 0, but the return type is tricky: its return type is functional pointer whose return type is again a function pointer whose return type is tmp<int>.

like image 880
JP Zhang Avatar asked Dec 15 '17 15:12

JP Zhang


2 Answers

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  |       _______
|_/  |      /  ___  \
|    |     /  /   \  \
|    |_____\  \_  /  /
 \          \____/  /_____
  \ _______________/______\.............................
like image 87
YSC Avatar answered Nov 11 '22 16:11

YSC


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.

like image 29
Barry Avatar answered Nov 11 '22 18:11

Barry