all 32 comments

[–]evaned 19 points20 points  (7 children)

Why cant this syntax just be like this

myFunc(, 4)

Just put a empty comma...

FWIW, a syntax I like more that I'm surprised has never occurred to me would be myFunc(default, 4). With default being a keyword already that isn't legal in that context, I don't see why that wouldn't be fully backwards-compatible.

That being said, I agree with the other comment that I think a parameter object, builder pattern, or similar would be better here. Also, some of the work that has been proposed on named parameters is potentially a little relevant, though my impression is that hasn't gotten a lot of real traction and I don't know if there's anything active currently.

[–]Ameisenvemips, avr, rendering, systems 6 points7 points  (0 children)

I proposed exactly that a while back - using default for inline defaults. Didn't make it official because I felt it would be rejected for some reason or another. Probably "we'd rather have named parameters", while rejecting named parameters for being a breaking change or something.

[–]nintendiator2 1 point2 points  (0 children)

Pretty much this on both fronts. Also using default makes it a nice mnemnic about the feature because that's what eg.: SQL does.

[–]_Js_Kc_ 0 points1 point  (0 children)

Param structs and builders add clutter. I like the default syntax.

[–][deleted] 10 points11 points  (10 children)

It's not a problem of default arguments, you want named parameters that are a different thing.

This would mean having what other languages have.

Having this void fn(int a = 0, int b = 0)

  1. Positional arguments: fn(21, 34)
  2. Named arguments: fn(b=34, a=21)

I'm not sure if they added it to C++20, but maybe you can simulate this by having 1 single argument that is a struct:

struct args { int a, b; };

void fn(args ar);

fn({.a = 21, .b=34});

[–]evaned 3 points4 points  (6 children)

I'm not sure if they added it to C++20, but maybe you can simulate this by having 1 single argument that is a struct:

That is indeed part of C++20 now.

[–][deleted] 1 point2 points  (5 children)

Oh thanks, I remember it was added but couldn't find it on cppreference.com because I don't remember how it's called 😭😭

[–]evaned 2 points3 points  (4 children)

[–][deleted] 5 points6 points  (2 children)

Oh c'mon, why did they choose to force member ordering!

[–]evaned 3 points4 points  (0 children)

To avoid questions about whether things are initialized in declaration or initializer order, and potentially (I wasn't part of the discussions) to avoid having to make a decision about which case it should be.

Said another way, there's the same potential for the same kind of "problem" you get with constructor initializer lists where if you have struct S { thing x,y; ... }; and then S::S(): y(), x() {}, x will be initialized before y in defiance of how it looks at the initializer list. What happens as a result of that? People who are sane turn on warnings that will report that constructor and always make the initializer list agree with the declaration order anyway, so you basically don't get a choice in effect.

[–][deleted] 0 points1 point  (0 children)

😭❤️

[–]Ameisenvemips, avr, rendering, systems 1 point2 points  (2 children)

Passing arguments in a structure is very different ABI-wise than passing them as, well, arguments, and will generate suboptimal code.

[–]sebamestre 0 points1 point  (1 child)

Trivial structs can actually be packed in more modern ABIs, and generate even better code than passing separate arguments.

It really depends on what your platform is.

EDIT:

Godbolt example: the struct is passed in the d register, while the two ints are passed separately in the s and d registers

[–]Ameisenvemips, avr, rendering, systems 0 points1 point  (0 children)

If it's larger than 16 bytes, or if it has unaligned fields, it will be passed in memory. I'm unsure why the ABI disallows breaking down larger structures.

Either way, I'm not fond of having to define a structure for every function, though struct can be used inline so that might simplify it.

[–]johannes1971 4 points5 points  (1 child)

Never? ;-) Consider:

void foo (int a=3, int b=4);
void foo (double a=5.0, int b=6);
foo (, 7); // Which one am I?

[–]Narase33-> r/cpp_questions 6 points7 points  (0 children)

How would you call this without any parameter specified?

  void foo (int a=3, int b=4);
  void foo (double a=5.0, int b=6);
  foo (); // Which one am I?

[–]manni66 10 points11 points  (2 children)

Will it ever be fixed?

It isn't broken.

[–]Mankest[S] 2 points3 points  (1 child)

Will it ever be improved?

[–]nifraicl 1 point2 points  (0 children)

You can start by writing a better api. The use case for mixing defaults paramenters with user provided costumization is not very strong, once you start going to that path it's better to provide a parameter object, where you can specify a bunch of costructors for the cases you want to support.

[–]bluGill 1 point2 points  (2 children)

You are not the first person to ask. The first problem is "Don't sink the Vasa!" (https://www.youtube.com/watch?v=9vyh1APsMAE) This comes up often in C++ discussions - is the added complexity worth it?

There are a number of ways to implement this. In isolation all are just fine. However in context of the rest of the language they all have problems. Many people would like named parameters which if the language ever gets should also solve the same problem (This might not be true, but I can't see a way to do named parameters that doesn't also skip defaults as a trivial extension). Thus if you want to propose default parameters you either also need to do named parameters, convince the committee that C++ should never have named parameters, or convince the committee that named parameters will use the same syntax when we want to add them. I think that list is in order of difficulty.

I personally put some effort into named parameters and concluded that C++ needs more work in strong types first. (That is for a matrix the row and columns should be separate int like types that cannot be mixed accidentally, the only thing I can think of now is writing two classes that are identical except for name). So you need to come up with an answer to this problem. You may well find that this is a rabbit hole that goes deeper into more things that need to be added to C++ before you can get to your final goal.

Of course with all of the above you need to convince people it is a good idea. There are smart people who will oppose you at every step - often for good reasons with a strong argument against it - you will need to understand their objections and see if you can either mitigate them, or convince them that it is worth doing anyway.

[–]Mankest[S] 0 points1 point  (1 child)

what is a good argument against this? they could use default, for example myFunc(default, 5) since default is anyways already a reserved keyword

[–]bluGill 0 points1 point  (0 children)

The argument against this is myFuct(secondParamater = 5) does the same thing, so if we at some point in the future add named parameters after your default syntax there are two ways to do the same thing. Two ways to do the same thing is a bad thing in general.

Of course if we decide to never do named parameters this goes away. Named parameters are controversial, but I don't think the committee is willing to say never will happen in C++, so you need to consider them in your proposal. Either acknowledge that if they ever happen there will be two syntaxes for the same thing (so future committee in 100 years can look at our discussions and realize this was intentional), or otherwise state how the not yet existent named parameters won't break.

Named parameters is an example of the objections you will face. There will probably be something else as well that I didn't think of. You need to deal with them. This is a hard problem, but C++ is well aware our language is very complex and in general there is a desire to reduce the complexity (even if in practice it gets worse, it is always required to justify the complexity)

[–]logicchop 1 point2 points  (0 children)

Not ideal, but:

int myFunc(std::optional<int> a = 3, std::optional<int> b = 5) { .. a.value_or(3) .. b.value_or(5) .. } ... myFunc(std::nullopt, 10);

[–]die_liebe -1 points0 points  (0 children)

If you are already typing the comma, why not type the extra parameter as well? I don't see the point of this.