digitalmars.D.learn - Distinguishing between const and non-const variable in a template?
- renoX <renosky free.fr> Feb 21 2007
- mario pernici <mario.pernici mi.infn.it> Feb 22 2007
- renoX <renosky free.fr> Feb 22 2007
- Deewiant <deewiant.doesnotlike.spam gmail.com> Feb 22 2007
- mario pernici <mario.pernici mi.infn.it> Feb 22 2007
- renoX <renosky free.fr> Feb 22 2007
- Chris Nicholson-Sauls <ibisbasenji gmail.com> Feb 22 2007
- Chris Nicholson-Sauls <ibisbasenji gmail.com> Feb 22 2007
- Tyler Knott <tywebmail mailcity.com> Feb 22 2007
- renoX <renosky free.fr> Feb 22 2007
Hello,
I'm trying to improve format string by allowing the format
" ... %{x} ...", my problem is that when I give a non-const char[]
parameter in
mixin(Putf!(foo));
then the template fail..
How can I reliably detect in a template if the parameter is a constant
or not?
My goal is:
if the parameter isn't a const char[]: leave its name unchanged so that
it's parsed by the writef at runtime, if it is a const char[]: parse it
myself with the new syntax.
Regards,
renoX
template FindChar(char[] A, char B) {
static if (A.length == 0) {
const int FindChar = -1;
} else static if (A[0] == B) {
const int FindChar = 0;
} else static if (-1 == FindChar!(A[1..$], B)) {
const int FindChar = -1;
} else {
const int FindChar = 1 + FindChar!(A[1..$], B);
}
}
template FmtString(char[] F, A...)
{
static if (F.length == 0)
static if (A.length)
const char[] FmtString = "\"," ~ Fmt!(A);
else
const char[] FmtString = "\"";
else static if (F.length == 1)
static if (A.length)
const char[] FmtString = F[0] ~ "\"," ~ Fmt!(A);
else
const char[] FmtString = F[0] ~ "\"";
else static if (F[0..2] == "%%")
const char[] FmtString = "%%" ~ FmtString!(F[2..$], A);
else static if (F[0..2] == "%{")
{
// get the variable name between %{ and }
static if (FindChar!(F, '}') <= 2)
static assert(0, "format %{} incorrect in '" ~ F ~ "'");
const char[] FmtString = "%s\"," ~ F[2..FindChar!(F,'}')] ~ ",\"" ~
FmtString!(F[1+FindChar!(F,'}')..$], A);
}
else
const char[] FmtString = F[0] ~ FmtString!(F[1..$], A);
}
template Fmt(A...)
{
//static assert(0, cast(char*)A[0]);
static if (A.length == 0)
const char[] Fmt = "";
else static if (is(typeof(A[0]) : char[]))
const char[] Fmt = "\"" ~ FmtString!(A[0], A[1..$]);
else static if (A.length == 1)
const char[] Fmt = A[0].stringof;
else
const char[] Fmt = A[0].stringof ~ "," ~ Fmt!(A[1..$]);
}
template Putf(A...)
{
const char[] Putf = "writef(" ~ Fmt!(A) ~ ");";
}
Feb 21 2007
renoX Wrote:Hello, I'm trying to improve format string by allowing the format " ... %{x} ...", my problem is that when I give a non-const char[] parameter in mixin(Putf!(foo)); then the template fail.. How can I reliably detect in a template if the parameter is a constant or not? My goal is: if the parameter isn't a const char[]: leave its name unchanged so that it's parsed by the writef at runtime, if it is a const char[]: parse it myself with the new syntax. Regards, renoX template FindChar(char[] A, char B) { static if (A.length == 0) { const int FindChar = -1; } else static if (A[0] == B) { const int FindChar = 0; } else static if (-1 == FindChar!(A[1..$], B)) { const int FindChar = -1; } else { const int FindChar = 1 + FindChar!(A[1..$], B); } } template FmtString(char[] F, A...) { static if (F.length == 0) static if (A.length) const char[] FmtString = "\"," ~ Fmt!(A); else const char[] FmtString = "\""; else static if (F.length == 1) static if (A.length) const char[] FmtString = F[0] ~ "\"," ~ Fmt!(A); else const char[] FmtString = F[0] ~ "\""; else static if (F[0..2] == "%%") const char[] FmtString = "%%" ~ FmtString!(F[2..$], A); else static if (F[0..2] == "%{") { // get the variable name between %{ and } static if (FindChar!(F, '}') <= 2) static assert(0, "format %{} incorrect in '" ~ F ~ "'"); const char[] FmtString = "%s\"," ~ F[2..FindChar!(F,'}')] ~ ",\"" ~ FmtString!(F[1+FindChar!(F,'}')..$], A); } else const char[] FmtString = F[0] ~ FmtString!(F[1..$], A); } template Fmt(A...) { //static assert(0, cast(char*)A[0]); static if (A.length == 0) const char[] Fmt = ""; else static if (is(typeof(A[0]) : char[])) const char[] Fmt = "\"" ~ FmtString!(A[0], A[1..$]); else static if (A.length == 1) const char[] Fmt = A[0].stringof; else const char[] Fmt = A[0].stringof ~ "," ~ Fmt!(A[1..$]); } template Putf(A...) { const char[] Putf = "writef(" ~ Fmt!(A) ~ ");"; }
Maybe you can use something like this const char[] s = "ab"; static if(is(typeof(&s))) { writefln(s, " not constant"); } else { static if(is(typeof(s))) { writefln(s, " constant"); } }
Feb 22 2007
mario pernici a écrit :renoX Wrote:Hello, I'm trying to improve format string by allowing the format " ... %{x} ...", my problem is that when I give a non-const char[] parameter in mixin(Putf!(foo)); then the template fail.. How can I reliably detect in a template if the parameter is a constant or not?
Maybe you can use something like this const char[] s = "ab"; static if(is(typeof(&s))) { writefln(s, " not constant"); } else { static if(is(typeof(s))) { writefln(s, " constant"); } }
Very nice, thanks! I'm curious: how did you find this?? I don't recall seeing it in the documentation and it looks kind of magical to me.. Thanks again, renoX
Feb 22 2007
renoX wrote:mario pernici a écrit :renoX Wrote:Hello, I'm trying to improve format string by allowing the format " ... %{x} ...", my problem is that when I give a non-const char[] parameter in mixin(Putf!(foo)); then the template fail.. How can I reliably detect in a template if the parameter is a constant or not?
Maybe you can use something like this const char[] s = "ab"; static if(is(typeof(&s))) { writefln(s, " not constant"); } else { static if(is(typeof(s))) { writefln(s, " constant"); } }
Very nice, thanks! I'm curious: how did you find this?? I don't recall seeing it in the documentation and it looks kind of magical to me.. Thanks again, renoX
He probably just figured it out: you can't take the address of a constant, so is(typeof(&s)) is false if s is a constant. I'm not sure about the necessity of the is(typeof(s)) in the else case, though. -- Remove ".doesnotlike.spam" from the mail address.
Feb 22 2007
Deewiant Wrote:renoX wrote:mario pernici a écrit :renoX Wrote:Hello, I'm trying to improve format string by allowing the format " ... %{x} ...", my problem is that when I give a non-const char[] parameter in mixin(Putf!(foo)); then the template fail.. How can I reliably detect in a template if the parameter is a constant or not?
Maybe you can use something like this const char[] s = "ab"; static if(is(typeof(&s))) { writefln(s, " not constant"); } else { static if(is(typeof(s))) { writefln(s, " constant"); } }
Very nice, thanks! I'm curious: how did you find this?? I don't recall seeing it in the documentation and it looks kind of magical to me.. Thanks again, renoX
He probably just figured it out: you can't take the address of a constant, so is(typeof(&s)) is false if s is a constant. I'm not sure about the necessity of the is(typeof(s)) in the else case, though.
I learned about static if (is(typeof(...))) from the post by Kirk McDonald in the recent thread "Testing if a function is defined in a module". The else clause static if(is(typeof(s))) is to make sure that s exists.
Feb 22 2007
mario pernici a écrit :Deewiant Wrote:renoX wrote:mario pernici a écrit :renoX Wrote:Hello, I'm trying to improve format string by allowing the format " ... %{x} ...", my problem is that when I give a non-const char[] parameter in mixin(Putf!(foo)); then the template fail.. How can I reliably detect in a template if the parameter is a constant or not?
Maybe you can use something like this const char[] s = "ab"; static if(is(typeof(&s))) { writefln(s, " not constant"); } else { static if(is(typeof(s))) { writefln(s, " constant"); } }
I'm curious: how did you find this?? I don't recall seeing it in the documentation and it looks kind of magical to me.. Thanks again, renoX
is(typeof(&s)) is false if s is a constant. I'm not sure about the necessity of the is(typeof(s)) in the else case, though.
I learned about static if (is(typeof(...))) from the post by Kirk McDonald in the recent thread "Testing if a function is defined in a module". The else clause static if(is(typeof(s))) is to make sure that s exists.
Mmm; how could s doesn't exist? D is supposed to be a statically typed language.. renoX
Feb 22 2007
renoX wrote:mario pernici a écrit :Deewiant Wrote:renoX wrote:mario pernici a écrit :renoX Wrote:Hello, I'm trying to improve format string by allowing the format " ... %{x} ...", my problem is that when I give a non-const char[] parameter in mixin(Putf!(foo)); then the template fail.. How can I reliably detect in a template if the parameter is a constant or not?
Maybe you can use something like this const char[] s = "ab"; static if(is(typeof(&s))) { writefln(s, " not constant"); } else { static if(is(typeof(s))) { writefln(s, " constant"); } }
I'm curious: how did you find this?? I don't recall seeing it in the documentation and it looks kind of magical to me.. Thanks again, renoX
constant, so is(typeof(&s)) is false if s is a constant. I'm not sure about the necessity of the is(typeof(s)) in the else case, though.
I learned about static if (is(typeof(...))) from the post by Kirk McDonald in the recent thread "Testing if a function is defined in a module". The else clause static if(is(typeof(s))) is to make sure that s exists.
Mmm; how could s doesn't exist? D is supposed to be a statically typed language.. renoX
version (Something) import some.convoluted.library; else import some.limited.standIn; // ... much later in module static if(is(typeof(someSymbolNotInStandIn))) { // ... do things usual way } else { // ... do it a work-around way for the stand in's case } -- Chris Nicholson-Sauls
Feb 22 2007
Chris Nicholson-Sauls wrote:renoX wrote:mario pernici a écrit :Deewiant Wrote:renoX wrote:mario pernici a écrit :renoX Wrote:Hello, I'm trying to improve format string by allowing the format " ... %{x} ...", my problem is that when I give a non-const char[] parameter in mixin(Putf!(foo)); then the template fail.. How can I reliably detect in a template if the parameter is a constant or not?
Maybe you can use something like this const char[] s = "ab"; static if(is(typeof(&s))) { writefln(s, " not constant"); } else { static if(is(typeof(s))) { writefln(s, " constant"); } }
I'm curious: how did you find this?? I don't recall seeing it in the documentation and it looks kind of magical to me.. Thanks again, renoX
constant, so is(typeof(&s)) is false if s is a constant. I'm not sure about the necessity of the is(typeof(s)) in the else case, though.
I learned about static if (is(typeof(...))) from the post by Kirk McDonald in the recent thread "Testing if a function is defined in a module". The else clause static if(is(typeof(s))) is to make sure that s exists.
Mmm; how could s doesn't exist? D is supposed to be a statically typed language.. renoX
version (Something) import some.convoluted.library; else import some.limited.standIn; // ... much later in module static if(is(typeof(someSymbolNotInStandIn))) { // ... do things usual way } else { // ... do it a work-around way for the stand in's case } -- Chris Nicholson-Sauls
Yes its a contrived example, but its possible. (And yes I know in this case version(Something) would be better than static-if, but what if the stand-in is subject to change without notice?) Another use case: a hypothetical GUI library that, in the absence of a main routine, uses its own generic one? (Wouldn't work all GUI lib designs, of course.) -- Chris Nicholson-Sauls
Feb 22 2007
renoX wrote:mario pernici a écrit :The else clause static if(is(typeof(s))) is to make sure that s exists.
Mmm; how could s doesn't exist? D is supposed to be a statically typed language.. renoX
D is statically typed, but that has nothing to do with why the second test is needed. Here's a quote from the language spec on the typeof(Expression) construct (http://www.digitalmars.com/d/declaration.html):Expression is not evaluated, just the type of it is generated: void func() { int i = 1; typeof(++i) j; // j is declared to be an int, i is not incremented printf("%d\n", i); // prints 1 }
And then if you look at the documentation for IsExpression, you'll see that invalid types used in the context of an IsExpression won't error, but instead cause the IsExpression to return 0 (false). When you combine these two properties, it is legal and valid for D code to take the type of an undeclared variable (resulting in an invalid type) inside an IsExpression; e.g.: void main() { int foo; static assert(is(typeof(foo)), "foo is a valid variable."); //Valid, doesn't trip static assert(is(typeof(undeclaredVariable)), "undeclaredVariable is invalid."); //Valid, trips typeof(foo) bar; //Valid, bar is an int typeof(undeclaredVariable) bar; //"Error: undefined identifier undeclaredVariable" } This is why two tests are required for Mario Pernici's const dectector. The first test determines if you can take the address of the variable, which fails for both const and invalid variables. Then, it needs to make sure the variable actually exists by taking its type (invalid variables will fail here, but everything else will pass).
Feb 22 2007
Tyler Knott a écrit :renoX wrote:mario pernici a écrit :The else clause static if(is(typeof(s))) is to make sure that s exists.
Mmm; how could s doesn't exist? D is supposed to be a statically typed language.. renoX
D is statically typed, but that has nothing to do with why the second test is needed. Here's a quote from the language spec on the typeof(Expression) construct (http://www.digitalmars.com/d/declaration.html): > Expression is not evaluated, just the type of it is generated: > void func() > { int i = 1; > typeof(++i) j; // j is declared to be an int, i is not incremented > printf("%d\n", i); // prints 1 > } And then if you look at the documentation for IsExpression, you'll see that invalid types used in the context of an IsExpression won't error, but instead cause the IsExpression to return 0 (false). When you combine these two properties, it is legal and valid for D code to take the type of an undeclared variable (resulting in an invalid type) inside an IsExpression; e.g.: void main() { int foo; static assert(is(typeof(foo)), "foo is a valid variable."); //Valid, doesn't trip static assert(is(typeof(undeclaredVariable)), "undeclaredVariable is invalid."); //Valid, trips typeof(foo) bar; //Valid, bar is an int typeof(undeclaredVariable) bar; //"Error: undefined identifier undeclaredVariable" } This is why two tests are required for Mario Pernici's const dectector. The first test determines if you can take the address of the variable, which fails for both const and invalid variables. Then, it needs to make sure the variable actually exists by taking its type (invalid variables will fail here, but everything else will pass).
Very clear explanation, thanks! renoX
Feb 22 2007









Chris Nicholson-Sauls <ibisbasenji gmail.com> 