On 01/15/13 12:21, bearophile wrote: > Artur Skawina: > >> Library territory. There's no need to put this in a D compiler. > > One of the threads about possible ways to allow to implement that in library > code: > > http://forum.dlang.org/thread/nxhsgwliuwdgidaou...@forum.dlang.org > > >> Except if you'd like to have 'printf("%.2g", d)' instead of >> 'printf!"%.2g"(d)' syntax. > > In some cases I don't mind a syntax like 'printf!"%.2g"(d)'. But I'd like D > to offer ways to remove/avoid template bloat in most of those cases.
You can't both avoid template bloat *and* statically check the arguments. Statically checking dynamic data is not possible, obviously. But it's not always a problem, as as long as everything is properly inlined the overhead can be /less/ than zero. Anyway, a way to do these check right now could be something like: auto printf(string fmt, A...)(A a) /*@inline*/ { static bool isFlag(char c) { switch (c) { case '0': case '#': case '-': case ' ': case '+': case '\'': case 'I': // Non-std. return true; default: return false; } } static bool checkArgs(B...)(string fmt) { if (!__ctfe) assert(0, "This function relies on bounds checks happening at CT"); while (fmt.length && fmt[0]!='%') fmt = fmt[1..$]; if (fmt.length==0) return true; static if (B.length==0) return fmt.length==0; else { size_t skip = 1; // Flags while (isFlag(fmt[skip])) ++skip; // Width while (fmt[skip]>='0' && fmt[skip]<='9') ++skip; // Precision // XXX skip \.[0-9]* , \.\*, \.[0-9]+\$ // Length modifier // XXX skip them. // Conversion spec if ( (fmt[skip]=='d' && is(B[0]==int)) || (fmt[skip]=='g' && is(B[0]==double)) || (fmt[skip]=='s' && is(typeof(cast()*B[0])==char)) /* XXX etc */ ) return checkArgs!(B[1..$])(fmt[skip+1..$]); assert(0, "printf format error: '" ~ fmt ~ "', remaining args: " ~ B.stringof); } } static assert(checkArgs!A(fmt), "Invalid or unsupported printf args"); import si = std.stdio, std.string; return si.printf(toStringz(fmt), a); } void main() { printf!"Pi == %d.%d != %3d\n"(3, 14, 314); printf!"Pi == %d.%d == %g\n"(3, 14, 3.14); printf!"Pi == %d.%d == %g == %s\n"(3, 14, 3.14, "3.14".ptr); // correctly flagged as invalid: //printf!"%"(42); } But ideally the syntax should be printf(A...)(static string s, A a) which would be "lowered" to the equivalent of printf(string s, A...)(A a) and similarly: printf(A...)(alias a, A a) should behave as print(alias a, A...)(A a) Having this work just for templated functions would probably be ok. artur