How to forward format specifiers ?

Element 126 via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Jun 29 04:55:38 PDT 2014


I am trying to define custom format specifiers (as described here [1]) 
for the following wrapper struct :

import std.stdio;
import std.format: formattedWrite, FormatSpec;
import std.string: format;

struct wrapper(T) {

	private T val;

	public this(T newVal) pure { val = newVal; }

	public void toString(
		scope void delegate(const(char)[]) sink,
		FormatSpec!char fmt
	) const
	{
		formattedWrite(sink, /+ Format string +/ , val);
	}
}

unittest {

	immutable uint base = 16;
	auto a = wrapper!uint(base);
	assert(format("%x", a) == format("%x", base));
	assert(format("%08x", a) == format("%08x", base));
}

More precisely, I want to forward the format specifier fmt received by 
wrapper!T.toString to formattedWrite.

Since formattedWrite expects a const(char)[] "string" as its second 
argument, I first naively tried to use :

	formattedWrite(sink, to!string(fmt), val);

but to!string(fmt) gives something similar to :
	
	address = 7FFFE91C54C0
	width = 0
	precision = 2147483646
	spec = x
	indexStart = 0
	indexEnd = 0
	flDash = false
	flZero = false
	flSpace = false
	flPlus = false
	flHash = false
	nested =
	trailing =

instead of the original format string, thus causing toString to fail at 
runtime.

The documentation for std.format [2] mentions a second prototype (among 
four) for toString :

	const void toString(
		scope void delegate(const(char)[]) sink,
		string fmt
	);

So I tried to modify wrapper!T.toString as follows :

	public void toString(
		scope void delegate(const(char)[]) sink,
		string fmt
	) const
	{
		formattedWrite(sink, fmt, val);
	}

but this one throws exception at runtime :

std.format.FormatException@/usr/include/dlang/dmd/std/format.d(2537): 
Expected '%s' format specifier for type 'wrapper!uint'.

I can make it work for simple cases by manually creating the format 
string using format() with the FormatSpec attributes, but this approach 
is not generic and will fail for complex format strings.

I've certainly missed something, but I can't figure out what is the 
right way to do it. What did I do wrong here ?

I remember having seen the "void toString(scope void delegate(/*...*/), 
/*...*/) const" prototypes being deprecated, but I don't know where it 
was. Maybe there is a better solution now ?


[1] http://wiki.dlang.org/Defining_custom_print_format_specifiers
[2] http://dlang.org/phobos-prerelease/std_format.html#.formatValue


More information about the Digitalmars-d-learn mailing list