www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Capturing __FILE__ and __LINE in a variadic templated function

reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
Is it possible to make the following definition

void show(alias T, string file = __FILE__, uint line = __LINE__, 
string fun = __FUNCTION__)()
{
     import std.stdio: writeln;
     try { debug writeln(file, ":",line, ":" /* , ": in ",fun */, 
" debug: ", T.stringof, ":", T); }
     catch (Exception) { }
}

used as

unittest
{
     int x = 11;
     int y = 12;
     int z = 13;
     show!x;
     show!y;
     show!z;
}

variadic so that it, instead, can be called as

unittest
{
     int x = 11;
     int y = 12;
     int z = 13;
     show!(x,y,z);
}

and still capture current file, line and function?
Nov 01 2015
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
Yeah, just make the other args normal runtime instead of template:

void show(T...)(string file = __FILE__, uint line = __LINE__, 
string fun = __FUNCTION__) {
   // same body
}

// same usage
Nov 01 2015
parent reply anonymous <anonymous example.com> writes:
On 01.11.2015 23:49, Adam D. Ruppe wrote:
 Yeah, just make the other args normal runtime instead of template:
Or make it two nested templates: template show(T ...) { void show(string file = __FILE__, uint line = __LINE__, string fun = __FUNCTION__)() { ... } }
Nov 01 2015
next sibling parent reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Sunday, 1 November 2015 at 23:36:15 UTC, anonymous wrote:
 On 01.11.2015 23:49, Adam D. Ruppe wrote:
 Yeah, just make the other args normal runtime instead of 
 template:
Or make it two nested templates: template show(T...) { void show(string file = __FILE__, uint line = __LINE__, string fun = __FUNCTION__)() { ... } }
Doesn't work. I need `T` to be an alias in order for .stringof to work. How do I specify a variadic template argument alias list of aliases?
Nov 02 2015
parent reply Gary Willoughby <dev nomad.so> writes:
On Monday, 2 November 2015 at 08:23:16 UTC, Nordlöw wrote:
 I need `T` to be an alias in order for .stringof to work.
typeof(T).stringof
Nov 02 2015
parent reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 2 November 2015 at 09:02:28 UTC, Gary Willoughby wrote:
 On Monday, 2 November 2015 at 08:23:16 UTC, Nordlöw wrote:
 I need `T` to be an alias in order for .stringof to work.
typeof(T).stringof
No, I want the variable name from the calling scope. This works for a single argument. void show(alias arg, string file = __FILE__, uint line = __LINE__, string fun = __FUNCTION__)() { import std.stdio: writeln; try { debug writeln(file, ":",line, ":" /* , ": in ",fun */, " debug: ", arg.stringof, " is ", arg); } catch (Exception) { } } unittest { int x = 11; show!x; } Prints dbg.d:80: debug: x is 11 My try at variadic template show(Args...) { void show(string file = __FILE__, uint line = __LINE__, string fun = __FUNCTION__)() { import std.stdio: write, writeln; try { debug write(file, ":",line, ":" /* , ": in ",fun */, " debug: "); foreach (const i, Arg; Args) { if (i) debug write(", "); // separator debug write(Arg.stringof, " is ", Arg); } debug writeln(); } catch (Exception) { } } } fails with compilation error dbg.d(83,5): Error: variable x cannot be read at compile time Why can't I make Args a sequence of aliases?
Nov 02 2015
parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Monday, 2 November 2015 at 09:16:09 UTC, Nordlöw wrote:
 On Monday, 2 November 2015 at 09:02:28 UTC, Gary Willoughby 
 wrote:
 On Monday, 2 November 2015 at 08:23:16 UTC, Nordlöw wrote:
 I need `T` to be an alias in order for .stringof to work.
typeof(T).stringof
No, I want the variable name from the calling scope. This works for a single argument. void show(alias arg, string file = __FILE__, uint line = __LINE__, string fun = __FUNCTION__)() { import std.stdio: writeln; try { debug writeln(file, ":",line, ":" /* , ": in ",fun */, " debug: ", arg.stringof, " is ", arg); } catch (Exception) { } } unittest { int x = 11; show!x; } Prints dbg.d:80: debug: x is 11 My try at variadic template show(Args...) { void show(string file = __FILE__, uint line = __LINE__, string fun = __FUNCTION__)() { import std.stdio: write, writeln; try { debug write(file, ":",line, ":" /* , ": in ",fun */, " debug: "); foreach (const i, Arg; Args) { if (i) debug write(", "); // separator debug write(Arg.stringof, " is ", Arg); } debug writeln(); } catch (Exception) { } } } fails with compilation error dbg.d(83,5): Error: variable x cannot be read at compile time Why can't I make Args a sequence of aliases?
Works for me on multiple compilers. To be precise, this worked: template show(Args...) { void show(string file = __FILE__, uint line = __LINE__, string fun = __FUNCTION__)() { import std.stdio: write, writeln; try { debug write(file, ":",line, ":" /* , ": in ",fun */, " debug: "); foreach (const i, Arg; Args) { if (i) debug write(", "); // separator debug write(Arg.stringof, " is ", Arg); } debug writeln(); } catch (Exception) { } } } unittest { int x = 11; show!x; }
Nov 02 2015
next sibling parent Daniel N <ufo orbiting.us> writes:
On Monday, 2 November 2015 at 09:54:50 UTC, John Colvin wrote:
 Why can't I make Args a sequence of aliases?
Works for me on multiple compilers. To be precise, this worked:
Except it prints Arg instead of x, try: debug write(Args[i].stringof, " is ", Arg);
Nov 02 2015
prev sibling parent reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 2 November 2015 at 09:54:50 UTC, John Colvin wrote:
 Works for me on multiple compilers. To be precise, this worked:

 template show(Args...)
 {
     void show(string file = __FILE__, uint line = __LINE__, 
 string fun = __FUNCTION__)()
     {
         import std.stdio: write, writeln;
         try
         {
             debug write(file, ":",line, ":" /* , ": in ",fun 
 */, " debug: ");
             foreach (const i, Arg; Args)
                 {
                 if (i) debug write(", "); // separator
                 debug write(Arg.stringof, " is ", Arg);
             }
             debug writeln();
         }
         catch (Exception) { }
     }
 }

 unittest
 {
     int x = 11;
     show!x;
 }
No. This prints: Arg is 11 I want it to print the name of Arg in the closing as x is 11 equivalent to what my single-parameter overload void show(alias arg, string file = __FILE__, uint line = __LINE__, string fun = __FUNCTION__)() { import std.stdio: writeln; try { debug writeln(file, ":",line, ":" /* , ": in ",fun */, " debug: ", arg.stringof, " is ", arg); } catch (Exception) { } } does.
Nov 02 2015
parent reply Daniel N <ufo orbiting.us> writes:
On Monday, 2 November 2015 at 11:36:27 UTC, Nordlöw wrote:
 I want it to print the name of Arg in the closing as

     x is 11
See my previous comment: Arg -> Args[i].stringof
Nov 02 2015
parent =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 2 November 2015 at 11:44:45 UTC, Daniel N wrote:
 On Monday, 2 November 2015 at 11:36:27 UTC, Nordlöw wrote:
 I want it to print the name of Arg in the closing as

     x is 11
See my previous comment: Arg -> Args[i].stringof
Ahh! Great! Thx!
Nov 02 2015
prev sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Monday, November 02, 2015 00:36:14 anonymous via Digitalmars-d-learn wrote:
 On 01.11.2015 23:49, Adam D. Ruppe wrote:
 Yeah, just make the other args normal runtime instead of template:
Or make it two nested templates: template show(T ...) { void show(string file = __FILE__, uint line = __LINE__, string fun = __FUNCTION__)() { ... } }
You should pretty much never use __FILE__ or __LINE__ as template arguments unless you actually need to. The reason is that it will end up creating a new instantiation of the template pretty much every time that it's used, which is going to be mean a _lot_ of extra code bloat if you use the template much. And in some, rare circumstances that may be exactly what you want. But it almost never is. - Jonathan M Davis
Nov 02 2015
next sibling parent =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 3 November 2015 at 06:14:14 UTC, Jonathan M Davis 
wrote:
 You should pretty much never use __FILE__ or __LINE__ as 
 template arguments unless you actually need to. The reason is 
 that it will end up creating a new instantiation of the 
 template pretty much every time that it's used, which is going 
 to be mean a _lot_ of extra code bloat if you use the template 
 much. And in some, rare circumstances that may be exactly what 
 you want. But it almost never is.

 - Jonathan M Davis
Ahh, thanks.
Nov 02 2015
prev sibling parent reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 3 November 2015 at 06:14:14 UTC, Jonathan M Davis 
wrote:
 You should pretty much never use __FILE__ or __LINE__ as 
 template arguments unless you actually need to. The reason is 
 that it will end up creating a new instantiation of the 
 template pretty much every time that it's used, which is going 
 to be mean a _lot_ of extra code bloat if you use the template 
 much. And in some, rare circumstances that may be exactly what 
 you want. But it almost never is.

 - Jonathan M Davis
So why is this pattern is used all over std.experimental.logger?
Nov 02 2015
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Tuesday, November 03, 2015 07:35:40 Nordlw via Digitalmars-d-learn wrote:
 On Tuesday, 3 November 2015 at 06:14:14 UTC, Jonathan M Davis
 wrote:
 You should pretty much never use __FILE__ or __LINE__ as
 template arguments unless you actually need to. The reason is
 that it will end up creating a new instantiation of the
 template pretty much every time that it's used, which is going
 to be mean a _lot_ of extra code bloat if you use the template
 much. And in some, rare circumstances that may be exactly what
 you want. But it almost never is.

 - Jonathan M Davis
So why is this pattern is used all over std.experimental.logger?
I don't know. I haven't looked at std.experimental.logger much. I do vaguely recall there being a discussion about that and there being something that prevented it from using __FILE__ and __LINE__ as runtime arguments, but I don't remember the reason. If I had to guess though, it would be be because of variadic arguments, since AFAIK, you can't have any function parameters after the variadic ones (even if they have default arguments), which makes it so that you can't put __FILE__ and __LINE__ as default arguments at the end like you'd normally do. Maybe that would be a good reason for a language enhancement that made it possible. It doesn't make sense when you want to be able provide arguments other than the default arguments to those trailing parameters, but it does make sense when you just want to use the default arguments - which really only makes sense with stuff like __FILE__ and __LINE__, but it would allow us to get rid of all of the template bloat that std.experimental.logger is going to generate if it's taking the __FILE__ and __LINE__ as template arguments. - Jonathan M Davis
Nov 03 2015