On 2015–08–16, at 1:29 AM, Nicol Bolas <jmck...@gmail.com> wrote:My only concern is that it could tie up more useful syntax. With Uniform Initialization syntax, you can perform value initialization and construction initialization. But there's no way to generically use default initialization. So we might someday want `f(default)` to mean "default initialize the parameter".
I think you should google better ;-)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1466.pdf
>
>
>
>
>
> --
>
> ---
> You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
> To post to this group, send email to std-pr...@isocpp.org.
> Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
I work on a codebase where this feature would have lots of use-cases, because we have lots of classes whose constructors have defaulted parameters:
C(int buffer_size = 1024, int timeout = 10, int tries = 3) : buffer_size_(buffer_size), timeout_(timeout), tries_(tries) {}
auto cptr = new C(); // usually the defaults are okayauto c2ptr = new C(2048); // use a bigger buffer
auto c3ptr = new C(1024, 1); // use the default buffer size but with a shorter timeoutauto c4ptr = new C(2048, 10, 5); // testing: bump up the number of tries
It would be marginally more convenient (and refactor-proof) to be able to write
auto cptr = new C(); // usually the defaults are okayauto c2ptr = new C(2048); // use a bigger buffer
auto c3ptr = new C(default, 1); // use the default buffer size but with a shorter timeoutauto c4ptr = new C(2048, default, 5); // testing: bump up the number of tries
However, I consider defaulted parameters in general to be a huge antipattern, and this constructor pattern in particular to be even worse.
I would MUCH rather just rewrite all these constructors so that they could be used as
auto cptr = new C(); // usually the defaults are okayauto c2ptr = new C().withBufferSize(2048); // use a bigger buffer
auto c3ptr = new C().withTimeout(1); // use the default buffer size but with a shorter timeoutauto c4ptr = new C().withBufferSize(2048).withTries(5); // testing: bump up the number of tries
or
auto cptr = new C(); // usually the defaults are okayauto c2ptr = new C(C::BufferSize(2048)); // use a bigger buffer
auto c3ptr = new C(C::Timeout(1)); // use the default buffer size but with a shorter timeoutauto c4ptr = new C(C::BufferSize(2048), C::Tries(5)); // testing: bump up the number of tries
f(default,2,default,4);
I would also wanna solve this with named arguments
f(.b = 2, .d = 4)
And index based
f([1] = 2, [3] = 4)
Am 15.08.2015 18:49 schrieb "Arthur Tchaikovsky" <atch...@gmail.com>:
>
And if you support the default indicator here, please allow it in aggregate initialization aswell to mean either value initialize or take the inclass initializer.
El 18/8/2015 6:26, "Arthur Tchaikovsky" <atch...@gmail.com> escribió:
>
> @dgutson
> I've typed the phrase in google, nothing came up on first page.
> So to your reply I say:
> I think you should be more polite, and instead of say what you've just said, you should say:
> "Hi, I've already proposed something identical really, great to have someone who thinks along the same lines ;)"
>
> But no, instead of being civilized and pleasant you've decided to post smart as** comment. And you consider yourself a professional? Unbelievable.
I'm just someone with different sense of humor and who wrote something that also considered overloading more than 10 years ago. You might wonder now why the proposal didn't suceed then, in case you become unoffended.
Am 18.08.2015 11:42 schrieb "Arthur Tchaikovsky" <atch...@gmail.com>:
>
> That genuinely seems pointless/silly to me, unless you can provide some convincing use cases.
>
These are designated initializers and why stop at making initialization uniform just before designated initializers?
It seems natural to me to allow them in function argument lists including for constructors. And the index notion looks like an elegant solution to skip arguments.
That genuinely seems pointless/silly to me, unless you can provide some convincing use cases.
On Tuesday, 18 August 2015 10:34:39 UTC+1, Johannes Schaub wrote:I would also wanna solve this with named arguments
f(.b = 2, .d = 4)
And index based
f([1] = 2, [3] = 4)
I gotta be honest with you Johann, I simply don't buy it.
And index notion looks anything but elegant solution. That is my opinion of course.
"I would MUCH rather just rewrite all these constructors"
But did you do it or simply wish that at some point you will find the time (and will) to do it, but in the mean time you are still using those "old" constructors? Because I also would MUCH rather have C++ cleaned up, yet this will never happen, and I need to use C++ in its current state. What I wish is very different to what I have.
And as for you saying that defaulted constructors are antipattern, is that a fact or it is simply your opinion?
I dear to disagree with the statement that the following example is self documenting and easier to read:
auto c3ptr = new C{.timeout = 1};
How is this^^^ easier to read? And how is this self documenting? Only on surface it seems that it is, both, but when you really think about it it is neither self documenting nor easy to read. Why? Because having only one argument initialized in {}, that is .timeout, leaves us with question, is that the only argument to that class, or are there any other?
If so, are those arguments inited by default? If so, how many? Etc.
Compared to this:
auto c3ptr = new C(default, 1); // use a shorter timeout
It is immediately obvious how many arguments there are and which one of them are default. And as for self documentation?
auto c3ptr = new C(default, /*timeout*/1); // use a shorter timeout
Hi,
Does anyone see helpfulness of such solution:
Having fnc:
void f(int a = 0, int b = 1, int c = 2, int d = 3);
I think that it would be nice to be able to say whilst calling it and requiring only some of those args to be non-default:
f(default,2,default,4);
Thoughts?
Earlier in this thread there were workarounds listed which are more or less comparable to the proposal in their effect.
I would like to elaborate some more on one of these workarounds, as it can be mapped pretty much 1-to-1 to the proposal and it happens to be the solution I employ when encountering this kind of problem.
# Current workaround.
struct s {
static int const default_a = 1337;
static int const default_b = 4096;
s(int a = default_a, int b = default_b)
: a(a), b(b) { }
int a;
int b;
};
int main() {
s x;
s y(42);
s z(s::default_a, 42);
return 0;
}
See working code here: http://ideone.com/OKtbuc
# Using the proposed syntax.
struct s {
s(int a = 1337, int b = 4096)
: a(a), b(b) { }
int a;
int b;
};
int main() {
s x;
s y(42);
s z(default, 42);
return 0;
}
The current solution has a number of drawbacks.
1) It's unnecessarily verbose.
2) It's easy to mess up for parameters that have the same type. (`s z(s::default_b, 42)` - Oops, passed `default_b` as `a`.)
3) When looking up the actual default values there is one more hop to make. It's not sufficient to look at the function declaration but additionally we have to look for e.g. default_a.
struct s {
int a = 1337;
int b = 4096;
};
int main() {
s x;
s y { 42 }; // or s y { .a = 42 };
s z { .b = 42 };
return 0;
}
--
--
---
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/3iegpTsMuT0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.
On 2015–08–20, at 7:53 AM, Arthur O'Dwyer <arthur....@gmail.com> wrote:On the subject of C and named parameters, I'll add that Ben Klemens' "21st Century C" shows a very nice idiom for getting Python-style named parameters out of a C99 compiler. I'm paraphrasing from memory a bit in the code sample below…
On 2015–08–20, at 7:53 AM, Arthur O'Dwyer <arthur....@gmail.com> wrote:On the subject of C and named parameters, I'll add that Ben Klemens' "21st Century C" shows a very nice idiom for getting Python-style named parameters out of a C99 compiler. I'm paraphrasing from memory a bit in the code sample below…Perhaps the syntax of an expression-list beginning with “.” should indicate implicit braces, added as sugar. I think that passing a struct is a superior design when lots of parameters are present, and one supported by decades of experience.
parameters value{.buffer_size = 100, .timeout = 2, .tries = 3};
Hi, Does anyone see helpfulness of such solution: Having fnc: void f(int a = 0, int b = 1, int c = 2, int d = 3); I think that it would be nice to be able to say whilst calling it and requiring only some of those args to be non-default: f(default,2,default,4); Thoughts?
f(int buffer_size = 1024, int timeout = 10, int tries = 3); f(default_t, int timeout = 10, int tries = 3) { return f(1024, timeout, tries); } f(int buffer_size, default_t, int tries = 3) { return f(buffer_size, 10, tries); } f(); f(default_, 0); f(default_, default_, 20); The function provider can use constant for the defaults of course but the useof the constants is however error prone. IMO, this kind of approach should appear in a possible proposal as your proposal solves all the issues of this approach. Vicente
On 2015–08–20, at 11:59 AM, Nicol Bolas <jmck...@gmail.com> wrote:What you're doing is enforcing a single struct policy, which is not something I would want to see advocated or become commonplace. However, it does lack the terrible syntactic noise of the C version, so it's already ahead of the curve ;)
The problem with that is that NSDMI's operate by effectively modifying constructors.
As for the implicit braces thing, that sounds like a very bad idea. Uniform initialization already has way too many implicit braces, to the point where it actually gets non-uniform. It's two extra characters; I don't see it as provoking that much syntactic noise.
On 2015–08–20, at 11:59 AM, Nicol Bolas <jmck...@gmail.com> wrote:What you're doing is enforcing a single struct policy, which is not something I would want to see advocated or become commonplace. However, it does lack the terrible syntactic noise of the C version, so it's already ahead of the curve ;)One is better than zero… but what’s the impediment to grouping by nested sub-aggregates?The problem with that is that NSDMI's operate by effectively modifying constructors.Since C++14, NSDMIs have a second method of action, by aggregate initialization. They are already allowed in aggregates.
Hmm, are you for the proposal or against? Implicit braces are the entirety of it. (Note that Clang and GCC already implement designated initializers, both only issuing a warning under -pedantic.)As for the implicit braces thing, that sounds like a very bad idea. Uniform initialization already has way too many implicit braces, to the point where it actually gets non-uniform. It's two extra characters; I don't see it as provoking that much syntactic noise.
And they specifically don’t apply under brace (uniform) initialization.
f(param_set1{...});
f(param_set2{...});
The problem with adding designated initializers alone is that they enhance aggregates but not classes with constructors. This impedes refactoring an aggregate into a non-aggregate, which is a very common operation.
non_aggregate nagg = {.param1 = 20, .param3 = 50};
On 2015–08–20, at 9:57 PM, Nicol Bolas <jmck...@gmail.com> wrote:Thus, this proposal must include designated initializers for aggregates.
And they specifically don’t apply under brace (uniform) initialization.
I don't know which "they" you're referring to: designated initializers or brace elision.
I'm going to assume that you mean to say that designated initializers should be restricted to function calls, without explicit braced-init-lists. If that's not the case, then just ignore this section.
I don't like the idea of hacking up a "solution" to named parameters this way (admittedly, a solution that many other languages use). But I'd be much happier with this if such a solution was just a natural outgrowth of a generally useful feature like designated aggregate initializers.
Here's a possible solution:
If the initializer list contains designated initializers, then it will attempt to use aggregate initialization on the target object type. If the target object is not an aggregate, then it will check all of the constructors for the target. If it finds a constructor that takes only one parameter (minus defaults of course) which is an aggregate, then it will initialize an aggregate and pass it to that constructor.
You could even recursively apply those rules. If a constructor takes one argument that has a constructor that takes one argument that has a constructor that takes one argument that is an aggregate, then the initializer list constructs that type, passes it to the next object, then passes the result to the next, and so on.