Declarators. Yes, declarators. They are the source of a lot of coding convention debates. It’s a really good topic for arguments — C++ doesn’t rule which one is better than the other (it doesn’t care!). And so we can write these without worrying someone might make fun of you:
int x;
int& a = x;
int &b = x;
int* c = &x;
int *d = &x;
In syntactical terms, b and d are “more valid” than the others. We are required to put declarator modifiers before the names:
int m, *n; // m is an int; n is a pointer to int
But the tide seems to turned in favor of one. With C++11’s variadic templates, the position of declarators seems to be restricted to the form where the modifiers are closer to the base type:
template<typename... Ts>
void VariadicFuncRef(const Ts&... args) { }
^
template<typename... Ts>
void VariadicFuncPtr(Ts*... args) { }
^
It is an error to write these forms:
template<typename... Ts>
void VariadicFuncRef(const Ts... &args) { }
template<typename... Ts>
void VariadicFuncPtr(Ts... *args) { }
For a concrete example, click here.
And so, my question is this:
Why are we limited to this (the legal) form and can’t use the other?
Any thoughts guys?
ADDITIONAL 1: I’m also interested on the design decision on why is this “rule” “enforced”.
First of all, I would not say that
int &ais more valid thanint& a. You may say it is more readable, or a good practice, but that is a different thing altogether.Second, the parameter unpack syntax
T...can be read as “the type-pattern on the left side of...is expanded, forming same or different actual function parameter types matching the form of the type-pattern”. So when you writef(T&...), it can be expanded tof(int&, float&, double&, Xyz&, Abc&). But that doesn’t seem to be so obvious (at least to me) when the syntax isT...&. So maybe, that is one of the several other possible reasons why the Standard made it like that.Also note that
argsinT&...argsis optional. So if you don’t write it, thenvoid f(T...&)looks weird (to me, at least) andvoid f(T&...)looks better aesthetically at least.You could also compare syntaxes like :
T * const & ...withT... * const &. The type-pattern is more obvious in the former syntax than in the latter.