12

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>.

Barry
  • 286,269
  • 29
  • 621
  • 977
JP Zhang
  • 767
  • 1
  • 7
  • 27
  • you are making a function pointer so you have to define everything in a function and * are for pointers and dereferencing of pointers. – Jake Freeman Dec 15 '17 at 15:41
  • 3
    For a start, code gets easier to read if you ident it properly ;) – Oliver Charlesworth Dec 15 '17 at 15:41
  • 1
    Possible duplicate of [Complex C declaration](https://stackoverflow.com/questions/15111526/complex-c-declaration) or https://stackoverflow.com/questions/1893013/complex-declarations or https://stackoverflow.com/questions/1448849/how-do-i-understand-complicated-function-declarations or etc. – underscore_d Dec 15 '17 at 15:44
  • 5
    "I don't understand the complex function in the second code example." that is exactly the point; the complex function declaration is unreadable (barring specific training to read it). Hence use the alternative. – Yakk - Adam Nevraumont Dec 15 '17 at 16:08

4 Answers4

24

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.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • I'm fairly sure that you can do that with `typedef` as well, though I don't know for sure. I'm also fairly sure it works in C++, too. – Nic Dec 15 '17 at 22:18
  • 2
    @QPaysTaxes The point is having a *nice* syntax. `typedef int(*A)();` is not a nice syntax. – Barry Dec 15 '17 at 22:28
  • True, but you don't have that in C, which I just realized I accidentally called C++. Whoops. – Nic Dec 15 '17 at 22:40
  • @QPaysTaxes Yeah, that's why they call it C++. It's one better :-) – Barry Dec 16 '17 at 01:13
  • and *significantly* more than one page longer – Nic Dec 16 '17 at 01:52
17

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  |       _______
|_/  |      /  ___  \
|    |     /  /   \  \
|    |_____\  \_  /  /
 \          \____/  /_____
  \ _______________/______\.............................
YSC
  • 38,212
  • 9
  • 96
  • 149
5

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.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
5

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.

iBug
  • 35,554
  • 7
  • 89
  • 134