www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Capturing caller's file/line number in variadic template functions

reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
I'm writing some unittests with very repetitive tests for a myriad of
different types, so I wrote a helper function:

	version(unittest) {
		void checkConsistency(T...)(T args) {
			foreach (a; args) {
				assert(isConsistent(a));
			}
		}
	}
	unittest {
		A a;
		B b;
		C c;
		checkConsistency(a,b,c);
	}

However, when a consistency check fails, the assert error points to
checkConsistency instead of the unittest, so it's a pain trying to
figure out exactly which test case failed. I tried adding default
arguments to checkConsistency:

	void checkConsistency(T...)(T args, string file=__FILE__,
		size_t line=__LINE__) { ... }

but this causes compile errors because when C==string, then the call is
ambiguous.

Is there an easy of working around this?


T

-- 
To err is human; to forgive is not our policy. -- Samuel Adler
Mar 16 2012
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 16 March 2012 at 18:21:54 UTC, H. S. Teoh wrote:
 	void checkConsistency(T...)(T args, string file=__FILE__,
 		size_t line=__LINE__) { ... }

 but this causes compile errors because when C==string, then the 
 call is
 ambiguous.

 Is there an easy of working around this?

Put the string file = blaha in the template argument list, before the variadic. voic checkConsistency(string file = __FILE__, int line = __LINE__, T...)(T t) {
Mar 16 2012
next sibling parent reply Kevin Cox <kevincox.ca gmail.com> writes:
On Mar 16, 2012 2:29 PM, "Adam D. Ruppe" <destructionator gmail.com> wrote:
 Put the string file = blaha in the template argument list,
 before the variadic.

 voic checkConsistency(string file = __FILE__, int line = __LINE__,

T...)(T t) {

But then you have to write it each time.
Mar 16 2012
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 16 March 2012 at 18:31:58 UTC, Kevin Cox wrote:
 But then you have to write it each time.

Nah, it just works, at least for the implicit calls: checkConsistency(1, "2", 3); // calls checkConsistenct!(__FILE__, __LINE__, int, string, int)(1, "2", 3);
Mar 16 2012
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Mar 16, 2012 at 02:31:47PM -0400, Kevin Cox wrote:
 On Mar 16, 2012 2:29 PM, "Adam D. Ruppe" <destructionator gmail.com> wrote:
 Put the string file = blaha in the template argument list,
 before the variadic.

 voic checkConsistency(string file = __FILE__, int line = __LINE__,

T...)(T t) {

But then you have to write it each time.

No you don't. The compiler automatically infers the compile-time arguments for you. This works: int a; char b; float c; checkConsistency(a,b,c); // Gets translated to: checkConsistency!(__FILE__, __LINE__, int, char, float)(a,b,c); exactly as I wanted. T -- People say I'm arrogant, but they're just ignorant fools.
Mar 16 2012
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 16 Mar 2012 14:23:37 -0400, H. S. Teoh <hsteoh quickfur.ath.cx>  
wrote:

 I'm writing some unittests with very repetitive tests for a myriad of
 different types, so I wrote a helper function:

 	version(unittest) {
 		void checkConsistency(T...)(T args) {
 			foreach (a; args) {
 				assert(isConsistent(a));
 			}
 		}
 	}
 	unittest {
 		A a;
 		B b;
 		C c;
 		checkConsistency(a,b,c);
 	}

 However, when a consistency check fails, the assert error points to
 checkConsistency instead of the unittest, so it's a pain trying to
 figure out exactly which test case failed.

I know this is already answered, but do you get a stack trace? Shouldn't the second stack frame point to the offending line? -Steve
Mar 16 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Mar 16, 2012 at 02:30:25PM -0400, Steven Schveighoffer wrote:
[...]
 I know this is already answered, but do you get a stack trace?
 Shouldn't the second stack frame point to the offending line?

[...] I didn't compile with debugging turned on, so it only showed a hex address. Using compile-time args for __FILE__ and __LINE__ lets me see the offending line even when debug is off. (And actually, the offending line is several frames down; the top few frames look like unittest scaffolding the compiler inserted for catching assert errors and handling unittest-specific stuff. Kinda painful to figure out where the problem is if a straight error message will tell you immediately. :-)) T -- Indifference will certainly be the downfall of mankind, but who cares? -- Miquel van Smoorenburg
Mar 16 2012
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 16 Mar 2012 14:41:40 -0400, H. S. Teoh <hsteoh quickfur.ath.cx>  
wrote:

 On Fri, Mar 16, 2012 at 02:30:25PM -0400, Steven Schveighoffer wrote:
 [...]
 I know this is already answered, but do you get a stack trace?
 Shouldn't the second stack frame point to the offending line?

[...] I didn't compile with debugging turned on, so it only showed a hex address. Using compile-time args for __FILE__ and __LINE__ lets me see the offending line even when debug is off. (And actually, the offending line is several frames down; the top few frames look like unittest scaffolding the compiler inserted for catching assert errors and handling unittest-specific stuff. Kinda painful to figure out where the problem is if a straight error message will tell you immediately. :-))

Right, but I dislike this sort of boilerplaty stuff, especially for unit tests. It should be avoidable... -Steve
Mar 16 2012
prev sibling parent "Yuri Gorobets" <yuri.gorobets gmail.com> writes:
On Friday, 16 March 2012 at 18:21:54 UTC, H. S. Teoh wrote:
 	void checkConsistency(T...)(T args, string file=__FILE__,
 		size_t line=__LINE__) { ... }

 but this causes compile errors because when C==string, then the 
 call is
 ambiguous.

Does it make sense to consider to add a new type to hold the file name and line? So the types clash can be avoided: class file_line { this(string f=__FILE__, size_t ln=__LINE__) { file = f; line = ln; } string file; size_t line; }; void checkConsistency(T...) (T args, file_line pos = new file_line) {...} checkConsistency!(A,B,C)(a,b,c); Seems to work, but requires an explicit checkConsistency call - I didn't manage to make it implicit.
Mar 16 2012