The riches of c++ expressiveness and syntax, make it somewhat difficult to use multiple features of the language on a single signature.
For example I'd like to declare a member function[1] as being :
virtualoverride // example of a context keywordnoexceptconstIt gets more complicated if we consider that functions can also be
[[deprecated]]The standard's wording looks Greek to me and even that was not true, I can't know what works with what (or what's a syntactic mishap, eg [1] might even be illegal).
I know that reading individual features (override, noexcept etc) will help, but is there a guide on how to use them in coaction ? (syntactically speaking; I don't expect/want an answer on the functionallity of the features)
Just in case it helps, I think the excerpt to be deciphered is the following
8.4.1 Function definitions have the form
function-definition: attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt function-body
If you have a copy of the spec, you can look for the grammar in each section. It sounds like you want a complete guide to what is and is not correct, and the spec is the only real source for this information. Fortunately, it's not that difficult to read, it's just time-consuming and tedious.
Here is the grammar for function definitions, taken from the beginning of section 8.4.1 of N3690. I suggest reading a primer on context-free grammars first (Wikipedia - skip to the examples). Note that everybody has their own variation on how they write context-free grammars, so the grammar in the C++ spec will be a little different from what you see in, say, Wikipedia or a compilers textbook.
function-definition:
attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt function-body
function-body:
ctor-initializeropt compound-statement
function-try-block
= default ;
= delete ;
Reading this, we see that "function-body" has four alternatives, one on each line. Two alternatives = delete and = default, so those go in the same place that a { ... } more interesting function body would go. (The function try block is a bit of an obscure way of defining a function in C++, so let's just ignore it.)
For "function-definition", you can see it has one line, so there is only one way to define a function. Each item in the line has to appear in order. Parts with the "opt" subscript are optional. So,
static, int, extern...)function_name(int x, int y) -> int)override or final){ ... } as well as = delete and = default)Once you have a little practice reading CFGs, it becomes second nature. The only hard part is jumping around the C++ spec to find all of the definitions you want.
Also note that the grammar will only tell you the syntax. If you just read the grammar, you'll write nonsense like:
// permissible, according to the grammar
extern static const void long short int int x;
Reading the text will explain that you can't, e.g., have a short long, even though it's permitted by the grammar.
The other trick is finding the definition you're looking for. As Serthy asks below, how do you specify pure functions? Where does = 0 go? Well, you can find that = 0 appears in section 9.2 as pure-specifier, but it can only appear on a member-declarator. So it can't appear in function-definition, it can only appear in a "declaration". The declaration and definition syntax is slightly different.
In other words, you can't define a pure function, but you can declare a pure function.
If you are interested in this subject, I recommend Compilers: Principles, Techniques and Tools by Alfred V. Aho, Ravi Sethi and Jeffrey D. Ullman.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With