www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to concatenate a tuple of strings at compile time?

reply paul <paul example.com> writes:
Hi!

How to concatenate  a tuple of strings at compile time?

Appending to an enum or an immutable string in a static foreach 
doesn't work. (And shadowing the thing doesn't work either) a)
Calling a function recursively doesn't work because I had to turn 
the tuple into an array which cannot be read at compile time. b)

a)
enum/immutable string connected;
static foreach(item; __traits(something))
   connected ~= item;

b)
string concat(string[] a, string b = "", index i = 0)
{
   if (s.length - 1 == index)
   {
      return b ~ a[$-1];
    } else {
      return concat(a,b[index],index+1);
    }
}
concat([__traits(something)]);

An internet search didn't reward any solution but probably I'm 
just missing something very trivial.
Any clues would be very appreciated. Thanks.

On a different note, what I want to achieve is to automatically 
generate a function call that hides the fact of a struct being 
initialized.

something like this:

struct X
{
   int a;
   string b;
}

class C
{
   X _x;

   this(int a, string b)
   {
     _x = X(a, b);
   }
}
Jan 06 2018
next sibling parent reply user1205 <user1205 1205.nc> writes:
On Saturday, 6 January 2018 at 19:35:33 UTC, paul wrote:
 Hi!

 How to concatenate  a tuple of strings at compile time?
 [...]
Hello, this simple template does the job: ``` template staticCat(T...) if (T.length) { static if (T.length == 1) enum staticCat = T[0]; else static if (T.length == 2) alias staticCat = staticCat!(T[0] ~ T[1]); else static if (T.length > 2) alias staticCat = staticCat!(T[0] ~ T[1], T[2..$]); } enum elems1 = tuple("foo", "bar"); enum elems2 = tuple("0", "1", "2"); enum elems3 = tuple("a"); ``` pragma(msg, staticCat!(elems1.expand)); pragma(msg, staticCat!(elems2.expand)); pragma(msg, staticCat!(elems3.expand)); There might be other solutions, maybe even in std.meta.
Jan 06 2018
parent reply user1205 <user1205 1205.nc> writes:
On Saturday, 6 January 2018 at 21:35:19 UTC, user1205 wrote:
 On Saturday, 6 January 2018 at 19:35:33 UTC, paul wrote:
 Hi!

 How to concatenate  a tuple of strings at compile time?
 [...]
Hello, this simple template does the job: ``` template staticCat(T...) if (T.length) { static if (T.length == 1) enum staticCat = T[0]; else static if (T.length == 2) alias staticCat = staticCat!(T[0] ~ T[1]); else static if (T.length > 2) alias staticCat = staticCat!(T[0] ~ T[1], T[2..$]); } enum elems1 = tuple("foo", "bar"); enum elems2 = tuple("0", "1", "2"); enum elems3 = tuple("a"); ``` pragma(msg, staticCat!(elems1.expand)); pragma(msg, staticCat!(elems2.expand)); pragma(msg, staticCat!(elems3.expand)); There might be other solutions, maybe even in std.meta.
There is also this one, less verbose, more efficient (not recursive template instances): ``` template staticCat(T...) if (T.length) { import std.array; enum staticCat = [T].join(); } enum elems1 = tuple("foo", "bar"); enum elems2 = tuple("0", "1", "2"); enum elems3 = tuple("a"); pragma(msg, staticCat!(elems1.expand)); pragma(msg, staticCat!(elems2.expand)); pragma(msg, staticCat!(elems3.expand)); ```
Jan 06 2018
parent reply user1205 <user1205 1205.nc> writes:
On Saturday, 6 January 2018 at 21:38:41 UTC, user1205 wrote:
 On Saturday, 6 January 2018 at 21:35:19 UTC, user1205 wrote:
 On Saturday, 6 January 2018 at 19:35:33 UTC, paul wrote:
 Hi!

 How to concatenate  a tuple of strings at compile time?
 [...]
Hello, this simple template does the job: ``` template staticCat(T...) if (T.length) { static if (T.length == 1) enum staticCat = T[0]; else static if (T.length == 2) alias staticCat = staticCat!(T[0] ~ T[1]); else static if (T.length > 2) alias staticCat = staticCat!(T[0] ~ T[1], T[2..$]); } enum elems1 = tuple("foo", "bar"); enum elems2 = tuple("0", "1", "2"); enum elems3 = tuple("a"); ``` pragma(msg, staticCat!(elems1.expand)); pragma(msg, staticCat!(elems2.expand)); pragma(msg, staticCat!(elems3.expand)); There might be other solutions, maybe even in std.meta.
There is also this one, less verbose, more efficient (not recursive template instances): ``` template staticCat(T...) if (T.length) { import std.array; enum staticCat = [T].join(); } enum elems1 = tuple("foo", "bar"); enum elems2 = tuple("0", "1", "2"); enum elems3 = tuple("a"); pragma(msg, staticCat!(elems1.expand)); pragma(msg, staticCat!(elems2.expand)); pragma(msg, staticCat!(elems3.expand)); ```
+1 Yeah i upvote myself. Best solution so far. Maybe tweak the constraint.
Jan 06 2018
parent user1205 <user1205 1205.nc> writes:
On Saturday, 6 January 2018 at 21:41:56 UTC, user1205 wrote:
 On Saturday, 6 January 2018 at 21:38:41 UTC, user1205 wrote:
 On Saturday, 6 January 2018 at 21:35:19 UTC, user1205 wrote:
 On Saturday, 6 January 2018 at 19:35:33 UTC, paul wrote:
 Hi!

 How to concatenate  a tuple of strings at compile time?
 [...]
``` template staticCat(T...) if (T.length) { import std.array; enum staticCat = [T].join(); } enum elems1 = tuple("foo", "bar"); enum elems2 = tuple("0", "1", "2"); enum elems3 = tuple("a"); pragma(msg, staticCat!(elems1.expand)); pragma(msg, staticCat!(elems2.expand)); pragma(msg, staticCat!(elems3.expand)); ```
+1 Yeah i upvote myself. Best solution so far. Maybe tweak the constraint.
BTW rule of thumb: when you have the choice between template metaprogramming and CTFE use CTFE, it's faster. The solution based on std.array.join is CTFE.
Jan 06 2018
prev sibling next sibling parent visitor <visitor gmail.com> writes:
On Saturday, 6 January 2018 at 19:35:33 UTC, paul wrote:
 Hi!

 How to concatenate  a tuple of strings at compile time?
Something like that maybe ? import std.stdio; import std.meta; enum connected = () { auto something = AliasSeq!("one", "two", "three"); string res = ""; static foreach(item; something) {{ res ~= item; }} return res; }(); void main() { writefln("connected = %s", connected); }
Jan 06 2018
prev sibling parent paul <paul example.com> writes:
Thanks for the input.

Unfortunately I still can't convince the compiler. __traits 
allMembers includes functions. Trying to filter those with 
std.traits.isCallable, it complains about strings that can't be 
read or fields that can't be accessed at compile time. Affected 
are both solutions.

So any insight in why mixin(fullyQualifiedName!T ~ "." ~ item) 
produces a compiler error saying that string can't be accessed at 
compile time would be very appreciated.

Same goes for [tuple(..)].filter!(item => 
!isCallable!(mixin(fullyQualifiedName!T ~ "." ~ item))).join;
Jan 06 2018