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".
The old declarator syntax was simply one rule with insignificant white space, but your idea is two. I doubt the committee would be in favor of having two rules when one would be sufficient.
The choice of putting the declarator on the left was most likely made for two reasons:
int* x
rather than int *x
(Bjarne uses the former for example). Most consider declarator syntax a mistake....
, not to the right.First of all, I would not say that int &a
is more valid than int& 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 write f(T&...)
, it can be expanded to f(int&, float&, double&, Xyz&, Abc&)
. But that doesn't seem to be so obvious (at least to me) when the syntax is T...&
. So maybe, that is one of the several other possible reasons why the Standard made it like that.
Also note that args
in T&...args
is optional. So if you don't write it, then void f(T...&)
looks weird (to me, at least) and void f(T&...)
looks better aesthetically at least.
You could also compare syntaxes like : T * const & ...
with T... * const &
. The type-pattern is more obvious in the former syntax than in the latter.
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
-- Antoine de Saint-Exupery
The difficulty in programming language design is not to add features, it is to refrain from adding them. Every feature, every variation of syntax, has a cost:
The syntax in C and C++ is (mostly) whitespace insensitive, therefore it does not matter where you place the &
or *
and both preferences can coexist without extra burden; however in the case of variadic templates it does matter because of the ...
token. The comittee thus decided to pick one, and they picked the most idiomatic in C++ (which put emphasis on the full type rather than the base type).
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