On Thu, Nov 12, 2009 at 1:00 PM, Walter Bright <newshou...@digitalmars.com> wrote: > Walter Bright wrote: >> >> Bill Baxter wrote: >>> >>> Any other thoughts about how to get the failure info? This is >>> probably the main complaint against __traits(compiles), that there's >>> no way to find out what went wrong if the code doesn't compile. Often >>> it can just be a typo. I know I've spent plenty of time looking at >>> static if(__traits(compiles, ...)) checks that weren't working only to >>> discover I switched an x for a y somewhere. Or passed the wrong >>> number of arguments. >> >> I agree it's a problem. Perhaps we can do: >> >> __traits(compiles_or_msg, ...) >> >> which would print the error messages, at least making it easier to track >> down. > > Eh, scratch that dumb idea. Just remove the __traits(compiles, ...) and > replace it with ..., and you'll get the message!
Maybe that is enough combined with a const code snippet enum code = q{ R r; // can define a range object if (r.empty) {} // can test for empty r.popFront; // can invoke next auto h = r.front; // can get the front of the range } static if (__traits(compiles, mixin(code))) { mixin(code); } else { pragma(msg, "Unable to instantiate code for type T=`"~T.stringof~"`:\n "~ code); pragma(msg, "Compiler reports:" ); mixin(code); } But I was really hoping for a separation of Interface definition and Interface verification. With the above you'll have to have two templates for every interface, like isForwardRange!(T) (evals to bool) and assertIsForwardRange!(T) (reports the compiler error or is silent). Hmm.... unless template assertIsInputRange(T, bool noisy=true) { enum code = q{ R r; // can define a range object if (r.empty) {} // can test for empty r.popFront; // can invoke next auto h = r.front; // can get the front of the range }; static if (!__traits(compiles, mixin(code))) { static if (noisy) { pragma(msg, "Type T=`"~T.stringof~"` doesn't support interface:\n "~ code); pragma(msg, "Compiler reports:" ); } mixin(code); } } template isInputRange(T) { enum bool isInputRange = __traits(compiles, assertIsInputRange!(T, false)); } And then we could wrap the whole shebang in a fancy code-generating string mixin and define things like the above using: mixin(DefineInterface( "InputRange", q{ R r; // can define a range object if (r.empty) {} // can test for empty r.popFront; // can invoke next auto h = r.front; // can get the front of the range })); mixin(DefineInterface!(assertIsInputRange)( "ForwardRange", q{ R r1; R r2 = r1; // can copy a range object }))); Writing DefineInterface is left as an exercise for the reader. :-) But it looks do-able. And DefineInterface could take a variadic list of assertIsXXX template aliases and generate code to check each one. --bb