1

What does the following c++ syntax means?

inline const Color (&EnumValuesColor())[3] {...}

Is it a function? I don't understand the syntax.

It is very different from the usual syntax type name(params){...}

It is generated from flatbuffers.

It is inside:

enum Color {
  Color_Red = 0,
  Color_Green = 1,
  Color_Blue = 2,
  Color_MIN = Color_Red,
  Color_MAX = Color_Blue
};

inline const Color (&EnumValuesColor())[3] { //<< here
  static const Color values[] = {
    Color_Red,
    Color_Green,
    Color_Blue
  };
  return values;
}

inline const char * const *EnumNamesColor() {
  static const char * const names[4] = {
    "Red",
    "Green",
    "Blue",
    nullptr
  };
  return names;
}

inline const char *EnumNameColor(Color e) {
  if (flatbuffers::IsOutRange(e, Color_Red, Color_Blue)) return "";
  const size_t index = static_cast<size_t>(e);
  return EnumNamesColor()[index];
}
//more codes... 

It is just the basic example from https://google.github.io/flatbuffers/flatbuffers_guide_tutorial.html

JaMiT
  • 14,422
  • 4
  • 15
  • 31
somebody4
  • 505
  • 4
  • 14
  • 1
    specifically - what has you puzzled? – Daniel A. White Jan 20 '21 at 03:22
  • @DanielA.White is it a function? I don't understand the syntax – somebody4 Jan 20 '21 at 03:32
  • It declares a function `EnumValuesColor` returning a const reference to an array of three `Color`. – WhozCraig Jan 20 '21 at 03:39
  • @WhozCraig Thanks, it is so different from the usual syntax `type name(params){...}` – somebody4 Jan 20 '21 at 03:45
  • @JaMiT so apparently this syntax is so obvious to everyone except me – somebody4 Jan 20 '21 at 03:52
  • @somebody4 No, it's not obvious. But it has several strange pieces, which makes it difficult to see which specifically is confusing you. Recognizing it as a function declaration is a good addition that was missing earlier. (Personally, I read the function body to see what it was returning before I dived into deciphering the syntax.) – JaMiT Jan 20 '21 at 03:53
  • Have a read of this: https://www.codeproject.com/Articles/7042/How-to-interpret-complex-C-C-declarations – Jerry Jeremiah Jan 20 '21 at 04:01
  • 4
    You have to read from inside to out and from right to left, So start with the inside paranthesis: `(&EnumValuesColor())` The inside of that is `EnumValuesColor` and then look to the right to find `()` and to the left to find `&`. So `EnumValuesColor` is a function returning a reference. Then look at the rest: `const Color (&EnumValuesColor())[3]`. The inside of that is the "a function returning a reference" and to the right is `[3]` (and array of three) and to the left is `Color` so we have "a function returning a reference to an array of three Color objects" – Jerry Jeremiah Jan 20 '21 at 04:02
  • 1
    My quest for a duplicate failed, but the syntax of `A::foo()` in [function returning reference to array](https://stackoverflow.com/questions/34439284/c-function-returning-reference-to-array) looks a bit similar... – JaMiT Jan 20 '21 at 04:05
  • Refer to [this C++ reference](https://en.cppreference.com/w/cpp) website, and read a good [C++ programming book](https://www.stroustrup.com/programming.html) – Basile Starynkevitch Jan 20 '21 at 04:05
  • 1
    Related: https://stackoverflow.com/questions/5398930/general-rules-of-passing-returning-reference-of-array-not-pointer-to-from-a-fu – Jerry Jeremiah Jan 20 '21 at 04:10

1 Answers1

3

Is it a function?

Yes.

Arrays have a bit wonky syntax in the C syntax that C++ inherited. The square brackets go to the very end of the declaration. Here is a variable example:

element_type variable_name [array_size];

Pointers and references also have wonky syntax especially when combined with arrays. The following is simple:

// array of pointers
element_type * variable_name [array_size];
// array of references - this is not allowed
element_type & variable_name [array_size];

But what if we want a reference (or pointer) to an array? We add parentheses around the name and the punctuator to signify that the it applies to the variable rather than the array element:

// pointer to array
element_type (* variable_name) [array_size];
// reference to array
element_type (& variable_name) [array_size];

Now on to functions. Arrays cannot be returned, but you can return pointer or reference to an array. Just like in the case of variables, the square brackets go to the end of the declaration - all the way after the parameter list. And parentheses surround not only the punctuator and name but also the parameter list:

// function that returns pointer to array
element_type (* function_name (parameter_list)) [array_size];
// function that returns reference to array
element_type (& function_name (parameter_list)) [array_size];

I would recommend not writing functions like this, but instead to take advantage of type aliases to make it easier to read:

using Color3 = Color[3];
inline const Color3 & EnumValuesColor();

Or use the std::array template:

inline const std::array<Color, 3> & EnumValuesColor();

Or std::span:

inline std::span<const Color, 3> EnumValuesColor();

To actually understand how any C-like declaration works, you could teach yourself the Clockwise/Spiral Rule. Frankly, I wouldn't bother unless you intend to write a C or C++ parser. Not understanding unnecessarily complex declarations makes it easier to prevent yourself from writing unreadable declarations yourself.

If you encounter something that you don't understand, let a program parse it for your: https://github.com/ridiculousfish/cdecl-blocks

eerorika
  • 232,697
  • 12
  • 197
  • 326