Jump to page: 1 2 3
Thread overview
Map one tuple to another Tuple of different type
Jul 20, 2014
Daniel Gibson
Jul 21, 2014
Vlad Levenfeld
Jul 21, 2014
Daniel Gibson
Jul 21, 2014
Vlad Levenfeld
Jul 21, 2014
Daniel Gibson
Jul 21, 2014
TheFlyingFiddle
Jul 21, 2014
TheFlyingFiddle
Jul 21, 2014
TheFlyingFiddle
Jul 21, 2014
Daniel Gibson
Jul 21, 2014
H. S. Teoh
Jul 21, 2014
bearophile
Jul 21, 2014
H. S. Teoh
Jul 22, 2014
Vlad Levenfeld
Jul 22, 2014
H. S. Teoh
Jul 22, 2014
Vlad Levenfeld
Jul 22, 2014
H. S. Teoh
Jul 22, 2014
Marc Schütz
Jul 22, 2014
Vlad Levenfeld
Jul 21, 2014
Daniel Gibson
Jul 21, 2014
H. S. Teoh
Jul 21, 2014
John Colvin
July 20, 2014
Hi,
I have a variadic templated function and want to call a C varargs function. I want to be able to pass static arrays, which D2 passes by value and C by reference, so I'd like to automagically translate those arguments.

My idea was something like this:

  extern (C) origFun(int x, ...);

  T transTupleElem(T)(T arg) { return arg; }

  float* transTupleElem(T : float[3])(T arg) {
    return arg.ptr;
  }

  void fun(T...)(int x, T argTuple) {
    // create a new tuple type that replaces all static float[3]
    // arrays with float* to emulate C call-by-reference behavior
    alias ReplaceAll!(float[3], float*, T) ModifiedTuple;
    ModifiedTuple modTuple;

    foreach(size_t i ; 0 .. T.length)
      modTuple[i] = transTupleElem(argTuple[i]); // BOOM!

    origFun(modTuple); // or is it modTuple.expand ?
  }

However, this doesn't work (dmd 2.065 linux64), because:
"Error: variable i cannot be read at compile time"

In C++11 (where almost everything else about variadic templates is pretty painful), this could probably be done like:
  template<typename... T>
  void fun(T... args)
  {
    origFun( transTupleElem(args)... );
  }
so I guess it shouldn't be too hard to do something equivalent in D?

I looked for some kind of staticMap() function that could map values from one tuple to another (of the same type), but only found std.typetuple.staticMap() which only seems to modify types in TypeTuples, not values in tuple instances.

Cheers,
Daniel
July 21, 2014
Thats real weird that it would reject your "i" variable, given that T.length is known at compile time. I think this is a bug. I can get your code to compile if I change your foreach loop to this:

foreach(i, U; T)
   modTuple[i] = transTupleElem(argTuple[i]); // ok
July 21, 2014
Am 21.07.2014 03:05, schrieb Vlad Levenfeld:
> Thats real weird that it would reject your "i" variable, given that
> T.length is known at compile time. I think this is a bug. I can get your
> code to compile if I change your foreach loop to this:
>
> foreach(i, U; T)
>     modTuple[i] = transTupleElem(argTuple[i]); // ok

That works indeeed.

I also tried "foreach(int i, x; argTuple)" which also with the same error as "foreach(i ; 0 .. T.length)".

As a workaround I created a TupleIndices template, that would return a tuple with 0 .. len and did "foreach(i; TupleIndices!(T.length)" but that was kinda messy and reminded me of the loops I had to jump through in C++ to do anything useful with variadic templates..

I agree that this is a bug, but at least your workaround is much nicer, thanks a lot! :-)

Cheers,
Daniel

(@Vlad: Originally I answered you directly because the Thunderbird developers thought it was a clever idea to put an "answer" button that answers to the author instead of to the newsgroup prominently into the GUI)
July 21, 2014
On Monday, 21 July 2014 at 01:29:40 UTC, Daniel Gibson wrote:
> Am 21.07.2014 03:05, schrieb Vlad Levenfeld:
>> Thats real weird that it would reject your "i" variable, given that
>> T.length is known at compile time. I think this is a bug. I can get your
>> code to compile if I change your foreach loop to this:
>>
>> foreach(i, U; T)
>>    modTuple[i] = transTupleElem(argTuple[i]); // ok
>
> That works indeeed.
>
> I also tried "foreach(int i, x; argTuple)" which also with the same error as "foreach(i ; 0 .. T.length)".
>
> As a workaround I created a TupleIndices template, that would return a tuple with 0 .. len and did "foreach(i; TupleIndices!(T.length)" but that was kinda messy and reminded me of the loops I had to jump through in C++ to do anything useful with variadic templates..
>
> I agree that this is a bug, but at least your workaround is much nicer, thanks a lot! :-)
>
> Cheers,
> Daniel
>
> (@Vlad: Originally I answered you directly because the Thunderbird developers thought it was a clever idea to put an "answer" button that answers to the author instead of to the newsgroup prominently into the GUI)

You're very welcome. The reason foreach(int i, x; argTuple) failed is because argTuple is a value (of type T), and so known only at run-time. To get a foreach to run at compile-time, you have to give it something whose value is known to the compiler (so, T and typeof(argTuple) would suffice, and 0..T.length really should as well).

A nice way to test is "pragma(msg, Foo)" where Foo is your argument... if its knowable at compile-time, then your compiler should output "Foo" (or the name of whatever its aliasing) to the console.
July 21, 2014
Am 21.07.2014 03:34, schrieb Vlad Levenfeld:
>
> You're very welcome. The reason foreach(int i, x; argTuple) failed is
> because argTuple is a value (of type T), and so known only at run-time.

Hmm but the only thing the compiler would need to know at compile-time is still i, which only depends on argTuple.length which is known at compile-time.

But ok, I can kinda understand that this doesn't work, probably foreach either operates completely on compile-time stuff (and does so statically) or completely on runtime-stuff, done dynamically.

> To get a foreach to run at compile-time, you have to give it something
> whose value is known to the compiler (so, T and typeof(argTuple) would
> suffice, and 0..T.length really should as well).

Yup

>
> A nice way to test is "pragma(msg, Foo)" where Foo is your argument...
> if its knowable at compile-time, then your compiler should output "Foo"
> (or the name of whatever its aliasing) to the console.

Thanks for the advice!

Cheers,
Daniel
July 21, 2014
On Monday, 21 July 2014 at 01:42:58 UTC, Daniel Gibson wrote:
> Am 21.07.2014 03:34, schrieb Vlad Levenfeld:
>> To get a foreach to run at compile-time, you have to give it something
>> whose value is known to the compiler (so, T and typeof(argTuple) would
>> suffice, and 0..T.length really should as well).
>
> Yup

I use this when i want a compile time foreach(from a constant number). It's slightly longer but has worked great for me thus far.

template staticIota(size_t s, size_t e, size_t step = 1)
{
    import std.typetuple : TypeTuple;
    static if(s < e)
	alias staticIota = TypeTuple!(s, staticIota!(s + step, e));
    else
	alias staticIota = TypeTuple!();
}


usage:

unittest
{
    foreach(i; staticIota!(0, 10))
    {
        pragma(msg, i);
    }
}

//Outputs 1 to 10 at compile-time.


July 21, 2014
On Monday, 21 July 2014 at 15:04:14 UTC, TheFlyingFiddle wrote:
>>//Outputs 1 to 10 at compile-time.
Edit: 0 to 9

July 21, 2014
On Monday, 21 July 2014 at 15:04:14 UTC, TheFlyingFiddle wrote:
> template staticIota(size_t s, size_t e, size_t step = 1)
> {
>     import std.typetuple : TypeTuple;
>     static if(s < e)
> 	alias staticIota = TypeTuple!(s, staticIota!(s + step, e, step));
>     else
> 	alias staticIota = TypeTuple!();
> }

Edit: Missed the second step.

July 21, 2014
Am 21.07.2014 17:04, schrieb TheFlyingFiddle:
> On Monday, 21 July 2014 at 01:42:58 UTC, Daniel Gibson wrote:
>> Am 21.07.2014 03:34, schrieb Vlad Levenfeld:
>>> To get a foreach to run at compile-time, you have to give it something
>>> whose value is known to the compiler (so, T and typeof(argTuple) would
>>> suffice, and 0..T.length really should as well).
>>
>> Yup
>
> I use this when i want a compile time foreach(from a constant number).
> It's slightly longer but has worked great for me thus far.
>
> template staticIota(size_t s, size_t e, size_t step = 1)
> {
>      import std.typetuple : TypeTuple;
>      static if(s < e)
>      alias staticIota = TypeTuple!(s, staticIota!(s + step, e));
>      else
>      alias staticIota = TypeTuple!();
> }
>
Yeah, I had a similar workaround:

template TupleIndicesImpl(alias len, I...)
{
  static if(len == I.length) // also handles len == 0
    alias TupleIndicesImpl = I;
  else static if(I.length == 0)
    alias TupleIndicesImpl = TupleIndicesImpl!(len, 0);
  else // I contains 0 ... I.length - 1, so add I.length
    alias TupleIndicesImpl = TupleIndicesImpl!(len, I, I.length);
}

template TupleIndices(alias len)
{
  alias TupleIndices = TupleIndicesImpl!(len);
}

foreach(i; TupleIndices!(myTuple.length) { ... }

At least for iterating over a tuple Vlad's way suggestion
("foreach(i, U; TupleType)") is nicer and more concise.

However, having something like staticIota in the stdlib would probably make sense.

Cheers,
Daniel
July 21, 2014
On Mon, Jul 21, 2014 at 12:55:34AM +0200, Daniel Gibson via Digitalmars-d-learn wrote:
> Hi,
> I have a variadic templated function and want to call a C varargs function.
> I want to be able to pass static arrays, which D2 passes by value and C by
> reference, so I'd like to automagically translate those arguments.
> 
> My idea was something like this:
> 
>   extern (C) origFun(int x, ...);
> 
>   T transTupleElem(T)(T arg) { return arg; }
> 
>   float* transTupleElem(T : float[3])(T arg) {
>     return arg.ptr;
>   }
> 
>   void fun(T...)(int x, T argTuple) {
>     // create a new tuple type that replaces all static float[3]
>     // arrays with float* to emulate C call-by-reference behavior
>     alias ReplaceAll!(float[3], float*, T) ModifiedTuple;
>     ModifiedTuple modTuple;
> 
>     foreach(size_t i ; 0 .. T.length)
>       modTuple[i] = transTupleElem(argTuple[i]); // BOOM!
> 
>     origFun(modTuple); // or is it modTuple.expand ?
>   }
> 
> However, this doesn't work (dmd 2.065 linux64), because: "Error: variable i cannot be read at compile time"
[...]

Try this:

	import std.typecons : staticIota;
	foreach (i; staticIota!(0, T.length))
		modTuple[i] = transTupleElem(argTuple[i]);


T

-- 
The volume of a pizza of thickness a and radius z can be described by the following formula: pi zz a. -- Wouter Verhelst
« First   ‹ Prev
1 2 3