On 01/13/2016 11:41 PM, Jacob Carlborg wrote:
> what if I need to format a third party type that I cannot add
> methods to? UFCS does not seem to work.
Here is an experiment that wraps the third party type to provide a lazy
toString:
import std.stdio;
import std.format;
import std.array;
import std.algorithm;
import std.range;
/* Wraps an element and provides a lazy toString that dispatches the
work to a
* user-provided 'formatter' function. E is the element type. */
struct Formatted(alias formatter, E) {
E element;
void toString(void delegate(const(char)[]) sink) const {
formatter(sink, element);
}
}
/* Adapts a range by converting the elements to 'Formatted'. R is the range
* type. */
auto formatted(alias formatter, R)(R range) {
return range.map!(e => Formatted!(formatter, ElementType!R)(e));
}
/* A third party test type that does not have a lazy toString member
* function. */
struct Foo {
double d;
string s;
}
void main() {
auto data = [ Foo(1.5, "hello"), Foo(2.5, "world") ];
auto buf = appender!string();
formattedWrite(buf, "%(%s\n%)",
data.formatted!(
(sink, a) => formattedWrite(sink, "%s and %s",
a.d, a.s)));
writeln(buf.data);
}
Prints the objects according to the user's lambda:
1.5 and hello
2.5 and world
It would be great if the user could provide just the format and accessed
the members:
data.formatted!("%s and %s", a.d, a.s); // <-- ERROR
But I couldn't get it working because the compiler does not know what
'a' is at that point. It might be acceptable to provide a lambda per
member but then it gets to cluttered:
data.formatted!("%s and %s", a => a.d, a => a.s); // Might work
Ali