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 :
virtual
override
// example of a context keywordnoexcept
const
It 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