I see the proposal to use the keyword 'default' as argument for function invocation, to explicit express the will to use the default argument, was already proposed multiple times, since https://wg21.link/N1466, and even in last years on this mailing list, e.g.:
https://lists.isocpp.org/std-proposals/2019/11/0708.php
https://lists.isocpp.org/std-proposals/2020/02/0969.php
https://lists.isocpp.org/std-proposals/2023/02/5607.php
Therefore, I guess to have no chance to have it considered, but I learned several points from such past threads.
In particular, on the one hand there is the alternative (still just a proposal) to explicit parameter names,
similarly to struct construction.
Well, IMHO, this also has problems (maybe easily solvable) as for example:
auto f(int x); //declaration
auto f(int y); //re-declaration
auto f(int w){} //definition
// what parameter name to be selected: x, y, or w ? Well, some restrictions may be forced in order to allow using it.
Another structural aspect is that the way overload resolution would change, as it would be based on names instead of just types. Doable, but likely hard to change the mindset in the community. I would not like that much.
On the other hand, mentioned threads also discuss the topic of non-forwardable 'default', as in the example:
struct C
{
C(int, float = 5.0f, int = 3);
};
std::optional<C> t(std::in_place, 2 /*, default, 1*/); //Second parameter of C constructor cannot be forwarded as default.
Well, I do not really want to force discussing again such a 'default', despite I still like it.
Let me move to the second part of the post.
Another keyword that might have been similarly extended is 'delete', aimed at forcing the compiler not to consider further parameters, e.g.:
void f(int, float = 1.); // #1
void f(int); // #2
f(2, delete); //selects #2 , no ambiguity
Not sure if a syntax like f[1](2); might have been more appealing to force the compiler selecting only overloads with one parameter.
For sure, it may mislead a reader to suppose f is an array of function pointers.
However, such a 'delete' is also not forwardable, so ... no way to get it, similarly to default.
Now, third part of the post, probably a potential proposal for which I ask to focus on during any answer.
Regardless of functions arguments, maybe there is room to consider and discuss using 'default', 'delete', ... and 'auto' for template arguments.
About 'default', I guess it was in the initial proposal of some of the old threads, but the discussion was then focused on function arguments only.
Do you believe that, even for templates, similar concerns and alternatives apply on 'default' (and 'delete') as for functions ?
Here the news for templates: 'auto'.
Have an explicit auto as template argument may have the goal to keep the compiler deducing corresponding parameter while being able to explicit next arguments, e.g.:
template<typename A, typename B, typename C>
void f(A, B, C);
f<int, auto, float>(a, b, c); // 'b' would be the only function argument leading to deduce a parameter type
An interesting extension would support the possibility to specify the number of arguments to match a parameter pack, so that multiple parameter packs may exist in a primary template, something like:
template<typename... T, typename... U>
class A{ /* some definition*/ }; // suppose T types and U types having a different semantic, as types of class data-members
going on:
template<typename... T, typename... U>
A<T..., U...> makeA(T&&... t, U&&... u);
makeA<auto...[2]>(3, 'c', 1.); // T pack will have size '2', therefore deduced as int and char, and U deduced as 1 type: double whereas a simple 'auto' would still lead T pack to the classic behaviour of grabbing all three types.
This seems barely in line with the pack indexing introduced in C++26.
The syntax auto[N] may be considered to be (one design choice only) equivalent to auto N times (comma separated). Well, likely hard to consider that auto...[N] and auto[N] would get to 'N' a different semantic ('N arguments for a single parameter pack' vs 'auto for N parameters'), but some more clearer solution may be discussed (e.g. auto...N for the former, or [N]auto for the latter), this topic is for a second phase of this discussion.
I don't know whether past proposals tried to introduce the alternative of parameter names even for templates as done for functions (e.g. templ<param1: type1>).
Anyway, the idea of a tool to explicit the number of types to match a pack seems interesting.
Fourth part of the post:
A final context for which 'default' and 'delete' can be used is in the initialization list for objects construction, to make it explicit the list of data members for which to use default values or no initialization (for non-class types).
This might increase the readability about the explicit will of the coder, therefore a better support for coding rules, e.g., in safety environments (about default), as better alternative with respect to implict relying on the default values associated to data members.
Different syntax may be proposed:
- a single 'default'/'delete' for each data member, e.g., dataMemberName{default}
- a single list of data members for each of two (default and delete), e.g., default(dataMemberName1, dataMemberName3)
Second solution is more compact but breaks the (non-standard) coding rules requiring for data members the same order as in class definition.
Not sure if 'delete' is appealing here. It would be 'not initialized' for data members, instead of 'not instantiated' for function members.
I guess that 'default' for data-members is not considered evil as for function parameters, otherwise they would not have been introduced in C++11.
Well, I also understand that here we have risk of redundancy compared to the current way to specify default values, but 'delete' would still be an extension to support performance, instead of coding rules.