Last active
April 3, 2016 07:57
-
-
Save SeijiEmery/3b0b273e95851388ed136e95a790e378 to your computer and use it in GitHub Desktop.
minor d vs c++ comparison -- join() string function on variadic arguments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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