digitalmars.D.learn - expanding variadic into format
- Codifies (14/14) Oct 31 2018 I have a routine that was happily printing ASCII strings and
- rikki cattermole (3/21) Oct 31 2018 Just to confirm, format there is std.format:format right?
- Codifies (4/9) Oct 31 2018 thought I was using core.vararg and std.format both using
- rikki cattermole (12/21) Oct 31 2018 No. They use different variadics.
- Stanislav Blinov (11/20) Oct 31 2018 ...as in:
- Codifies (4/25) Oct 31 2018 thats fantastic thanks so much, can you explain a little more
- Stanislav Blinov (65/78) Oct 31 2018 As rikki already explained, std.format is a variadic template,
- Codifies (5/16) Oct 31 2018 thanks for this makes it a lot clearer, I'm guessing there is a
I have a routine that was happily printing ASCII strings and values using opengl, however I want to improve it so it can be used in the same manner as some other languages printf function... void printValue(Font fnt,float x, float y, string frmt, ...) { /* matrix math and other stuff removed for readability */ string message = format(frmt, _arguments); no surprise this naive attempt causes a runtime error as its trying to format a range using the first format specifier in frmt am I going to have to chop frmt into descrete chunks that have just one % symbol in them and then build up the formatted message string like that? is there some way to somehow transfer my input variadic into formats variadic ?
Oct 31 2018
On 01/11/2018 12:53 AM, Codifies wrote:I have a routine that was happily printing ASCII strings and values using opengl, however I want to improve it so it can be used in the same manner as some other languages printf function... void printValue(Font fnt,float x, float y, string frmt, ...) { /* matrix math and other stuff removed for readability */ string message = format(frmt, _arguments); no surprise this naive attempt causes a runtime error as its trying to format a range using the first format specifier in frmt am I going to have to chop frmt into descrete chunks that have just one % symbol in them and then build up the formatted message string like that? is there some way to somehow transfer my input variadic into formats variadic ?Just to confirm, format there is std.format:format right? Because that isn't using C variadics, its using template variadics.
Oct 31 2018
On Wednesday, 31 October 2018 at 11:56:31 UTC, rikki cattermole wrote:On 01/11/2018 12:53 AM, Codifies wrote:thought I was using core.vararg and std.format both using templates ??[...]Just to confirm, format there is std.format:format right? Because that isn't using C variadics, its using template variadics.
Oct 31 2018
On 01/11/2018 1:08 AM, Codifies wrote:On Wednesday, 31 October 2018 at 11:56:31 UTC, rikki cattermole wrote:No. They use different variadics. Template variadics happen on the template parameter side: void func(T...)(T args) { pragma(msg, T.length); pragma(msg, T.stringof); } C variadics happen on the function parameters side and are highly unsafe: void func(...) { } If you use core.vararg you're talking with C. If you use std.format you're talking D's template variadics.On 01/11/2018 12:53 AM, Codifies wrote:thought I was using core.vararg and std.format both using templates ??[...]Just to confirm, format there is std.format:format right? Because that isn't using C variadics, its using template variadics.
Oct 31 2018
On Wednesday, 31 October 2018 at 11:53:52 UTC, Codifies wrote:void printValue(Font fnt,float x, float y, string frmt, ...) { /* matrix math and other stuff removed for readability */ string message = format(frmt, _arguments);is there some way to somehow transfer my input variadic into formats variadic ?...as in: ``` void printValue(Args...)(Font fnt, float x, float y, string frmt, auto ref Args args) { // ... import std.functional : forward; string message = format(frmt, forward!args); // ... } ```Just to confirm, format there is std.format:format right? Because that isn't using C variadics, its using template variadics.
Oct 31 2018
On Wednesday, 31 October 2018 at 12:09:04 UTC, Stanislav Blinov wrote:On Wednesday, 31 October 2018 at 11:53:52 UTC, Codifies wrote:thats fantastic thanks so much, can you explain a little more about whats going on here ?void printValue(Font fnt,float x, float y, string frmt, ...) { /* matrix math and other stuff removed for readability */ string message = format(frmt, _arguments);is there some way to somehow transfer my input variadic into formats variadic ?...as in: ``` void printValue(Args...)(Font fnt, float x, float y, string frmt, auto ref Args args) { // ... import std.functional : forward; string message = format(frmt, forward!args); // ... } ```Just to confirm, format there is std.format:format right? Because that isn't using C variadics, its using template variadics.
Oct 31 2018
On Wednesday, 31 October 2018 at 12:13:57 UTC, Codifies wrote:On Wednesday, 31 October 2018 at 12:09:04 UTC, Stanislav Blinov wrote:As rikki already explained, std.format is a variadic template, which gets expanded into argument list at compile time. That's why it can't be used with C-syle variadics: when you passed _arguments, the expansion treated that as a single argument instead of a tuple. Therefore, to forward arguments to std.format, your `printValue` must also be a variadic. There are, broadly speaking, two ways to pass arguments to functions: by value and by reference. When you make a template like this: void foo(T)(T value) { /* ... */ } it will take the argument by value, making copies when necessary: struct S { /* ... */ } S s; foo(S.init); // calls foo without copying, argument is constructed directly foo(s); // copies `s` and passes that copy to `foo` If that template is defined like this: void foo(T)(ref T value) { /* ... */ } then it will *only* take argument by reference: foo(S.init); // error, 'ref' cannot bind to rvalue foo(s); // no copy is made, `foo` takes `s` by reference There are more subtleties, especially when taking `const ref` arguments, but I won't get into those. There's a special syntax for template functions: `auto ref` arguments. Those are deduced to be by-value or by-reference at compile time (see https://dlang.org/spec/template.html#auto-ref-parameters): void foo(T)(auto ref T value) { /* ... */ } foo(S.init); // works, compiles as foo(S); foo(s); // works, compiles as foo(ref S); But, because inside of function definition all arguments are lvalues, you lose this additional information if you pass them to another function directly. To preserve that information, there's a `forward` template in std.functional. D doesn't have rvalue references, so that template will still copy the bits of non-`ref` arguments, but it will not call postblits, etc (it `move`s them using std.algorithm.mutation.move). So, there are two possible ways to implement your print: // Take all Args by value, i.e. copy everything first time void printValue(Args...)(Font fnt, float x, float y, string frmt, Args args) { // make copies of every argument in `args` (again) and pass those to `format` auto message = format(frmt, args); } or // Infer whether each argument is an lvalue or not void printValue(Args...)(Font fnt, float x, float y, string frmt, auto ref Args args) { import std.functional : forward; // preserve lvalue/rvalue string message = format(frmt, forward!args); } Both allow you to accomplish your goal, but the second one only copies the argument bits when necessary. Getting into finer implementation nuances, conceptually this allows a function to even take and pass around non-copyable types as arguments. Sadly, this is not widely adopted by Phobos, which likes to make unnecessary copies. I.e. the `format` function itself takes Args by value, even though it probably should take advantage of this specific language feature. But at least calling it via `forward`, you only make necessary copies once, instead of twice.``` void printValue(Args...)(Font fnt, float x, float y, string frmt, auto ref Args args) { // ... import std.functional : forward; string message = format(frmt, forward!args); // ... } ```thats fantastic thanks so much, can you explain a little more about whats going on here ?
Oct 31 2018
On Wednesday, 31 October 2018 at 12:54:52 UTC, Stanislav Blinov wrote:On Wednesday, 31 October 2018 at 12:13:57 UTC, Codifies wrote:thanks for this makes it a lot clearer, I'm guessing there is a mailing list backing this web forum, as I replied missing some other responses.[...][...]As rikki already explained, std.format is a variadic template, which gets expanded into argument list at compile time. That's why it can't be used with C-syle variadics: when you passed _arguments, the expansion treated that as a single argument instead of a tuple. Therefore, to forward arguments to std.format, your `printValue` must also be a variadic. [...]
Oct 31 2018