Jump to page: 1 2 3
Thread overview
Variadic template arguments unpacking
Jul 06, 2013
Max Strakhov
Jul 06, 2013
Ali Çehreli
Jul 06, 2013
Ali Çehreli
Jul 06, 2013
Max Strakhov
Jul 06, 2013
Artur Skawina
Jul 06, 2013
Max Strakhov
Jul 06, 2013
Artur Skawina
Jul 06, 2013
Max Strakhov
Jul 06, 2013
TommiT
Jul 06, 2013
TommiT
Jul 06, 2013
TommiT
Jul 06, 2013
Max Strakhov
Jul 06, 2013
Artur Skawina
Jul 06, 2013
TommiT
Jul 06, 2013
Max Strakhov
Jul 07, 2013
Artur Skawina
Jul 06, 2013
TommiT
Jul 06, 2013
TommiT
Jul 06, 2013
TommiT
Jul 06, 2013
Max Strakhov
Jul 06, 2013
TommiT
July 06, 2013
Suppose, in c++ i've got a variadic template function F, and i want to convert all the arguments in some individual manner by function conv and pass all the converted arguments as a variadic list to another variadic template function G.
Then i just do the following:

template<typename T>
struct R;

template<typename T>
R<T>::Type conv(T&& val);

template<typename ... Args>
void F(Args&& ... args) {
    G(conv(std::forward<Args>(args))...);
}

Is there any way to do the same kind of thing in D? I couldn't find any unpacking operator or a library function to do so...
The problem is that i have to pass converted lits to a C-like variadic function, for example printf, so it would be like:

template<typename T>
struct R;

template<typename T>
R<T>::Type conv(T&& val);

template<typename ... Args>
void MyPrintf(const char * format, Args&& ... args) {
    printf(convFormat(format), conv(std::forward<Args>(args))...);
}

I hope, my point is clear enough.
July 06, 2013
On 07/05/2013 05:41 PM, Max Strakhov wrote:
> Suppose, in c++ i've got a variadic template function F, and i want to
> convert all the arguments in some individual manner by function conv and
> pass all the converted arguments as a variadic list to another variadic
> template function G.
> Then i just do the following:
>
> template<typename T>
> struct R;
>
> template<typename T>
> R<T>::Type conv(T&& val);
>
> template<typename ... Args>
> void F(Args&& ... args) {
>      G(conv(std::forward<Args>(args))...);
> }
>
> Is there any way to do the same kind of thing in D? I couldn't find any
> unpacking operator or a library function to do so...
> The problem is that i have to pass converted lits to a C-like variadic
> function, for example printf, so it would be like:
>
> template<typename T>
> struct R;
>
> template<typename T>
> R<T>::Type conv(T&& val);
>
> template<typename ... Args>
> void MyPrintf(const char * format, Args&& ... args) {
>      printf(convFormat(format), conv(std::forward<Args>(args))...);
> }
>
> I hope, my point is clear enough.

Here is one that works:

import core.stdc.stdio;
import std.string;

string convFormat(string s)
{
    return s ~ '\n';
}

void myPrintf(T...)(string s, T args)
{
    printf(convFormat(s).toStringz, args);
}

void main()
{
    myPrintf("format %d %f %c %s", 42, 1.5, 'a', "hello".toStringz);
}

Ideally, the caller of MyPrintf should not have to call toStringz on "hello", because myPrintf is a proper D function. However, I don't know how to manipulate args to call toStringz on string arguments.

More information is at

  http://dlang.org/template.html#TemplateTupleParameter

Ali

July 06, 2013
On 07/05/2013 06:35 PM, Ali Çehreli wrote:

> More information is at
>
>    http://dlang.org/template.html#TemplateTupleParameter

And the definitive document on templates is the following:

  https://github.com/PhilippeSigaud/D-templates-tutorial

Ali

July 06, 2013
On 07/06/13 02:41, Max Strakhov wrote:
> Suppose, in c++ i've got a variadic template function F, and i want to convert all the arguments in some individual manner by function conv and pass all the converted arguments as a variadic list to another variadic template function G.

http://forum.dlang.org/thread/yiougbmcegjlsrynlvyt@forum.dlang.org?page=2#post-mailman.1205.1371553020.13711.digitalmars-d-learn:40puremagic.com

artur
July 06, 2013
On Saturday, 6 July 2013 at 01:35:28 UTC, Ali Çehreli wrote:
> On 07/05/2013 05:41 PM, Max Strakhov wrote:
> Here is one that works:
>
> import core.stdc.stdio;
> import std.string;
>
> string convFormat(string s)
> {
>     return s ~ '\n';
> }
>
> void myPrintf(T...)(string s, T args)
> {
>     printf(convFormat(s).toStringz, args);
> }
>
> void main()
> {
>     myPrintf("format %d %f %c %s", 42, 1.5, 'a', "hello".toStringz);
> }

You only converted the format string with was not in the question. I need to convert all args by a template function, but your example is actually better than mine.
Suppose, i want my own string representation of primitive types, then in c++ i would write those two functions:
convFormat("format %d %f %c %s") -> std::string("format %s %s %s %s")
conv(42) -> std::string("int(42)")
conv(1.5)-> std::string("float(1.5)")
etc.
and the resulting printf:
template<typename ... Args>
void myPrintf(const char * format, Args&& ... args) {
   printf(convFormat(format).c_str(), conv(std::forward<Args>(args)).c_str()...);
}
And that would do the job. Can i somehow do the same thing in D?
July 06, 2013
Artur, if i use your solution like

printf("...", ForEach!(val => conv(val).c_str())(values).tuple);

Than i would get a crash, because all the tuple elements would be char*'s, pointing to already freed memory, as std::string's destructor gets called each time right after alias function exits. Ths is what c++ unpacking operator for: i actually return a packed list of std::string's, apply .c_str() to each and than unpack the list to current context.
July 06, 2013
On 07/06/13 14:21, Max Strakhov wrote:
> Artur, if i use your solution like
> 
> printf("...", ForEach!(val => conv(val).c_str())(values).tuple);
> 
> Than i would get a crash, because all the tuple elements would be char*'s, pointing to already freed memory, as std::string's destructor gets called each time right after alias function exits. Ths is what c++ unpacking operator for: i actually return a packed list of std::string's, apply .c_str() to each and than unpack the list to current context.

Can you show some simple code that exhibits the problem?

artur
July 06, 2013
Thanx for all your help, i just solved the problem with mixins like this:

string res = "";
for(i, rev v; args)
    res ~= string.format(", f(args[%d]).val()");
mixin("return G(" ~ res ~ ");");

Only without any actual looping and variables, so compiler could deal with it.
July 06, 2013
On Saturday, 6 July 2013 at 16:15:52 UTC, Max Strakhov wrote:
> Thanx for all your help, i just solved the problem with mixins like this:
>
> string res = "";
> for(i, rev v; args)
>     res ~= string.format(", f(args[%d]).val()");
> mixin("return G(" ~ res ~ ");");
>
> Only without any actual looping and variables, so compiler could deal with it.

printf("...", ForEach!(val => conv(val).c_str())(values).tuple);

...would have done exactly the same as C++:

printf("...", conv(values).c_str()...);

...does (barring it makes a temporary struct which holds one field for each of those converted const char pointers, but the compiler can optimize it away).
July 06, 2013
On Saturday, 6 July 2013 at 16:40:25 UTC, TommiT wrote:
> ...does (barring it makes a temporary struct which holds one field for each of those converted const char pointers, ...

Should be "...one field per each of those..."
« First   ‹ Prev
1 2 3