Point of declaration
After difficult posts about the coroutines and before yet another one I decided to take a break and write about something easier instead. This time we will have a look at one of the aspects of the declarations namely – point of declaration.
So what is this point of declaration? Intuitively it’s a point in the source code, since when the name of the declared entity is taken into account by the compiler. Usually, the point of declaration is after declarator and before initializer.
Ok, but what does it mean in practice? Standard gives us two examples of the source codes:
int i = 42;
{
int i = i;
}
I bet, that normally most of the C++ users will guess, that value of the i in the inner scope will be 42, but most probably this is not the case. If we split the statement into parts, then int i is a declarator and = i is initializer. Since declaration point is between them, it means, that the statement is declaring the value i and assigns its own value to itself. This of course results in the undefined behavior.
Another example of the code from the standard:
const int i = 2;
{ int i[i]; }
Now is it undefined behavior? It sure looks strange, but again following the mentioned rule the point of declaration is in fact in the place of the ;. This means, we are declaring an array of two integers named i.
Exceptions from the general rule
There are exceptions from the general rule, which are as follows:
Classes and enums have their point of declaration immediately after their name
This makes CRTP pattern possible:
struct TheOneRight : Singleton<TheOneRing>{/*...*/};
// ^ here is the declaration point
Aliases points of declarations are immediately after the type they point to
struct Test;
// ^ here is declaration point
void foo(){ using Test = Test; /*does nothing*/ }
// ^ here is the point of declaration
Enumerators point of declaration is after its complete definition
constexpr bool yes=true, no=false;
//^ ^here are declaration points
enum class Decision{yes = yes, no = no};
//^ ^ here are declaration points
enum class Incremental{first = 10, second = first+1};
// ^ ^ declaration points
Functions declaration point is before its body
void stack_eater(unsigned i){stack_eater(++i);}
//^ here is the declaration point
This allows to make recursive calls.
Template parameters’ declaration points are after the parameters are introduced
using T = unsigned char;
template<class T
= T // lookup finds the typedef name of unsigned char
, T // lookup finds the template parameter T
N = 0> struct A { };
Summary
This is the first post of the short C++ facts series, that I am going to continue. In this post, we have learned what is the point of declaration and it’s consequences on the code’s behavior. If you want to support me, there is nothing more motivating than feedback and a kind word :). You can contact me at dawid.pilarski@