Skip to content

Instantly share code, notes, and snippets.

@SeijiEmery
Last active April 3, 2016 07:57
Show Gist options
  • Save SeijiEmery/3b0b273e95851388ed136e95a790e378 to your computer and use it in GitHub Desktop.
Save SeijiEmery/3b0b273e95851388ed136e95a790e378 to your computer and use it in GitHub Desktop.
minor d vs c++ comparison -- join() string function on variadic arguments
// List of template arguments to string
struct Joiner {
string sep;
stringstream ss;
Joiner (string sep) : sep(sep) {}
template <typename T, typename... Args>
Joiner& apply (const T & v, Args... args) {
ss << v << sep;
apply(args...);
return *this;
}
template <typename T>
Joiner& apply (const T & v, Args... args) {
ss << v;
return *this;
}
template <>
Joiner& apply () { return *this; }
string str () { return ss.str(); }
}
template <typename... Args>
string join (string sep, Args... args) {
return Joiner(sep).apply(args).str();
}
void example () {
assert(join(", ", "foo", 1, 2.4) == "foo, 1, 2.4");
assert(join(", ", 2) == "2");
assert(join(", ") == "");
}
// Admittedly this isn't too bad, though it would get pretty hairy if we had to use partial
// template specialization and overloads to implement stringification (thankfully this is standardized
// with ostream overloads). And if we decided that we don't want to use stringstream (b/c it's slow),
// well... hmm.
// This is much simpler to do in D :)
string join (Args...)(string sep, Args args) {
import std.conv: to;
string joined = "";
// args is a tuple, so we can iterate directly
foreach (i, arg; args) {
if (i != 0) joined ~= sep;
joined ~= to!string(arg); // c++ equiv: to<string>(arg)
}
return joined;
}
// Though here's a direct translation of the C++ version, fwiw
struct Joiner {
string sep, joined;
this (string sep) { this.sep = sep; }
auto apply (T, Args...)(T v, Args args) {
joined ~= v ~ sep;
return apply(args);
}
auto apply (T)(T v) {
return joined ~= v;
}
auto apply () {
return joined;
}
}
auto join (Args...)(string sep, Args args) {
return Joiner(sep).apply(args);
}
unittest {
assert(join(", ", "foo", 1, 2.4) == "foo, 1, 2.4");
assert(join(", ", 2) == "2");
assert(join(", ") == "");
// And as a bonus:
class Foo {
string toString () { return "foo!"; }
}
struct Bar {
int x, y, z;
string toString () { return "bar!"; }
}
struct Baz {
int x, y, z;
}
assert(join(", ", new Foo(), Bar()) == "foo!, bar!");
assert(join(", ", new Foo(), [1, 2, 3]) == "foo!, [1, 2, 3]"); // to!string automatically handles array types
assert(join(", ", new Foo(), Baz(1, 2, 3), null) == "foo!, Baz(1, 2, 3), null"); // and struct types w/out toString implemented
// Note: arrays are still statically typed
assert(__traits(compiles, [1, 2, 3]));
assert(!__traits(compiles, ["1", 2, 3, new Foo()]));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment