2

I know that using type alias and typedef make the code so readable, less error-prone and easy modify. However in this example I want to know this complicated type:

#include <iostream>
#include <typeinfo>

char ( * (* x() )[] )();

int main(){

    std::cout << typeid(x).name() << std::endl;
}

As the rule of thumb says that I read it from inside through outside but I find it too confusing.

Can someone help me how to read it?

The output of GCC:

FPA_PFcvEvE
Itachi Uchiwa
  • 3,044
  • 12
  • 26
  • 5
    [https://cdecl.org/](https://cdecl.org/?q=char+%28+*+%28*+x%28%29+%29%5B%5D+%29%28%29%3B) – ForceBru Jul 24 '21 at 11:38
  • *"read it from inside through outside"* Yes, exactly. What confuses you? The only other thing you need to know is that stuff on the right (`[]`,`()`) has more precedence than stuff on the left (`*`), unless parentheses change that. – HolyBlackCat Jul 24 '21 at 11:44
  • @HolyBlackCat: Yes. so tell me the type please. – Itachi Uchiwa Jul 24 '21 at 11:50
  • Is it allowed for `)[]` to have no dimensions? – KamilCuk Jul 24 '21 at 11:58
  • @ItachiUchiwa *"tell me the type"* Look at the first comment. – HolyBlackCat Jul 24 '21 at 12:01
  • 1
    @HolyBlackCat -- re: "what confuses you?" -- the whole thing! I wouldn't trust myself to read that correctly without a great deal of work, or a trusted tool. Sure, you can learn how to do it, but some things just aren't worth the effort. – Pete Becker Jul 24 '21 at 12:42
  • @PeteBecker It only looks confusing until you learn it. IMO the rules are very simple and easy to remember (once you learn them). – HolyBlackCat Jul 24 '21 at 13:06
  • @HolyBlackCat Few people know c++ as well as Pete Becker does. (Did you see his credentials?) The point is, reading complex types is _ugly_ and requires applying many non-obvious rules in a certain order, jumping around, to pluck out a correct answer. That isn't beginner friendly--or even expert friendly. :( – Chris Uzdavinis Jul 24 '21 at 14:02
  • 1
    @ChrisUzdavinis Nope, I didn't, the credentials are impressive. Then I assume that *"great deal of work"* was an overstatement to make a point. The rules are simple in essense (start at the middle; go to the right until you hit the end or `)`; go to the left until you hit `(` or the beginning; if you were inside of `(` `)`, repeat). There could be complex cases where you need to stop and think (e.g. about where "the middle" is), but this is not one of them. – HolyBlackCat Jul 24 '21 at 14:30
  • 4
    @HolyBlackCat -- mostly, I don't want to have to figure that out (and I'm out of practice). I'd make the programmer who wrote it do it over again. [Unask the question](https://www.awakin.org/read/view.php?tid=583). – Pete Becker Jul 24 '21 at 14:51

2 Answers2

5
char        - returning a char                         *
  (*        - of pointers to                    *---v  ^
    (*      - returning a pointer to    *---v   ^   v  ^
       x()  - a function `x`          --^   v   ^   v  ^
    )[]     - an array                      *---^   v  ^
  )();      - functions                             *--^

And see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.array-type , like:

FPA_PFcvEvE
^           - function (
 ^          - returning pointer
  ^         - to an array [
  ><        - with no dimension expression
   ^        - separator, end of array ]
    ^       - of pointers
     ^      - to functions (
      ^     - returning char
       ^    - (void) functions that take no arguments
        ^   - separator, end of function )
         ^  - (void) it's a function that takes on arguments
          ^ - separator, end of function )

Example:

#include <iostream>

char return_a() { return 'a'; }
char return_b() { return 'b'; }
char return_c() { return 'c'; }

char (* array_of_funcs_that_return_char[3])() = {
    return_a,
    return_b,
    return_c,
};

char (* (*pointer_to_array_of_funcs_that_return_char)[3])() = &array_of_funcs_that_return_char;

char ( * (* x() )[3] )() {
    return pointer_to_array_of_funcs_that_return_char;
}

int main() {
    std::cout << (*x())[1](); // outputs 'b'
}
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
3

I made a small library to help decode complicated types into English-y std::string values. Just call type_to_string::describe<T>() and it will return a (mostly) human readable string describing the type T.

Here it is with your type:

// url-includes works with compiler explorer, not normal c++
#include <https://raw.githubusercontent.com/cuzdav/type_to_string/main/describe.hpp>

#include <iostream>
int main() {
    using X = char ( * (*() )[] )();
    std::cout << type_to_string::describe<X>() << std::endl;
}

Its output is:

function taking (), returning pointer to array[] of pointer to function taking (), returning char

see it live https://godbolt.org/z/6Kjf5jb7E

(The implementation is more detail than would be useful as part of an SO answer, but it's readable on my github at the link.)

Chris Uzdavinis
  • 6,022
  • 9
  • 16