Re: How in the name of D do you deal with more than one optional template parameter?

2018-10-31 Thread aliak via Digitalmars-d-learn

On Tuesday, 30 October 2018 at 21:19:13 UTC, H. S. Teoh wrote:
On Tue, Oct 30, 2018 at 08:46:31PM +, aliak via 
Digitalmars-d-learn wrote:

[...]


struct C(Args...)
	if ((rest.length == 2 && is(Args[0] == B!C, C) && is(Args[1] 
== string)) ||
	(rest.length == 1 && (is(Args[0] == B!C, C) || is(Args[0] 
== string

{
...
}



Hah! Yep. That.



[...]

[...]


This is unnecessary.  Why not just use `void` directly?


Ah true, yes brain fart on my part.

I think it was left overs from a scenario where I didn't want to 
do this:


static if (!is(T == void)) {
  T variable;
}

Because a Void struct would be declared as well. But then one 
realises that everywhere you want to use "variable" you need to 
guard it with a static if so meh.




struct C(string name, T, string desc)
if (is(T : B!C, C) || is(T == void))
{
...
}



[...]

[...]

You can also use default parameters for templates:

struct C(string name, T, string desc = null)
{
...
}

then you just need one more alias for the string-only variant:

alias C(string name, string desc) = C!(name, void, desc);

Note that this syntax is much shorter than the full eponymous 
template syntax, which makes it easier to deal with longer 
parameter lists:


Ah nice! Yes that helps indeed :)



	struct ManyParams(A a, B b=defaultB, C c=defaultC, D 
d=defaultD)

{
...
}
	alias ManyParams(A a, C c, D d=defaultD) = ManyParams!(a, 
null, c, d);
	alias ManyParams(A a, D d=defaultD) = ManyParams!(a, void, 
void, d);


And so on.

And there's probably a way to auto-generate those alias 
templates if you anticipate needing to do this many times. (Or 
if you're insane and want to let the user specify different 
arguments in any order.) Mixins and CTFE codegen FTW!  :-D


Did I hear "specify different arguments in any order"? -> 
https://forum.dlang.org/thread/cjbqrpbpymwayzcgc...@forum.dlang.org.


:p

Cheers,
- Ali





T




Re: How in the name of D do you deal with more than one optional template parameter?

2018-10-30 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Oct 30, 2018 at 08:46:31PM +, aliak via Digitalmars-d-learn wrote:
> Hi,
> 
> Do you guys have any strategies for dealing with templates when they
> have more than one optional  parameter?
> 
> E.g let's say we have a type C that takes three parameters
> 
> struct B(T) {}
> struct C(string name, T, string desc) {}
> 
> And let's say I want T and desc to be optional and T should be of type
> B, i.e. I would want to be able to do is this:
> 
> auto x = C!("name", B!int)();
> auto y = C!("name", B!int, "desc")();
> auto z = C!("name", "desc")();
> 
> So C is a template that must have a name, and can optionally have a B,
> or a description, or both.
> 
> The immediate (maybe naive) way that comes to mind is:
> 
> struct C(string name, rest...)
> if (rest.length <= 2)
> if (rest has one elements then it can be either template B or a string) //
> how?
> if (rest has two elements then it must be template B followed by string) //
> how?

struct C(Args...)
if ((rest.length == 2 && is(Args[0] == B!C, C) && is(Args[1] == 
string)) ||
(rest.length == 1 && (is(Args[0] == B!C, C) || is(Args[0] == 
string
{
...
}


[...]
> Giving it some more thought, one could do this too:
> 
> struct Void {}

This is unnecessary.  Why not just use `void` directly?

struct C(string name, T, string desc)
if (is(T : B!C, C) || is(T == void))
{
...
}


> Are there other ways? Or does anyone have any tips on how to deal with
> this?  Or is the alias way generally the way to go?
[...]

You can also use default parameters for templates:

struct C(string name, T, string desc = null)
{
...
}

then you just need one more alias for the string-only variant:

alias C(string name, string desc) = C!(name, void, desc);

Note that this syntax is much shorter than the full eponymous template
syntax, which makes it easier to deal with longer parameter lists:

struct ManyParams(A a, B b=defaultB, C c=defaultC, D d=defaultD)
{
...
}
alias ManyParams(A a, C c, D d=defaultD) = ManyParams!(a, null, c, d);
alias ManyParams(A a, D d=defaultD) = ManyParams!(a, void, void, d);

And so on.

And there's probably a way to auto-generate those alias templates if you
anticipate needing to do this many times. (Or if you're insane and want
to let the user specify different arguments in any order.) Mixins and
CTFE codegen FTW!  :-D


T

-- 
A mathematician is a device for turning coffee into theorems. -- P. Erdos


How in the name of D do you deal with more than one optional template parameter?

2018-10-30 Thread aliak via Digitalmars-d-learn

Hi,

Do you guys have any strategies for dealing with templates when 
they have more than one optional  parameter?


E.g let's say we have a type C that takes three parameters

struct B(T) {}
struct C(string name, T, string desc) {}

And let's say I want T and desc to be optional and T should be of 
type B, i.e. I would want to be able to do is this:


auto x = C!("name", B!int)();
auto y = C!("name", B!int, "desc")();
auto z = C!("name", "desc")();

So C is a template that must have a name, and can optionally have 
a B, or a description, or both.


The immediate (maybe naive) way that comes to mind is:

struct C(string name, rest...)
if (rest.length <= 2)
if (rest has one elements then it can be either template B or a 
string) // how?
if (rest has two elements then it must be template B followed by 
string) // how?

{
  static if (rest[0] is type B) {
enum hasB = true;
static if (rest.length > 1) {
  string desc = rest[1];
}
  } else {
enum hasB = false;
if (rest.length) {
  string desc = rest[1];
} else {
  string desc = null;
}
  }

  // Now I have access to a desc if it was provided
  // And a boolean that tells me if I have a B type.
  // But dayum that was a lot of hoops.
}

Giving it some more thought, one could do this too:

struct Void {}

struct C(string name, T, string desc)
if (isInstanceOf!(B, T) || is(T == Void)
{}
template C(string name T) {
  alias C = C!(name, T, null);
}
template C(string name, string desc) {
  alias C = C!(name, Void, desc);
}

Which requires one to create this meta-Void type to get to work. 
Which I guess is not that bad. But, anyway.


Are there other ways? Or does anyone have any tips on how to deal 
with this? Or is the alias way generally the way to go?


Cheers,
- Ali