digitalmars.D - Function pointer argument to function template
- Kirk McDonald (37/37) May 30 2006 By way of example, take this simple function template (taken from an
- Tom S (27/27) May 30 2006 Hey there :)
- Kirk McDonald (4/44) May 30 2006 Ah! The IsExpression! I hadn't remembered that at all from when I read
- Daniel Keep (12/52) May 30 2006 Wow. That's... so much nicer than mine. I'm not even going to post my
- Kirk McDonald (33/40) May 31 2006 In C++, at least (which, yes yes, is not D, but it is similar enough in
- Tom S (7/10) May 31 2006 Unfortunately I've got no idea as how to do it in a way that would
- Daniel Keep (71/83) May 31 2006 Actually, it's quite simple, if utterly evil. It involves abusing IFTI
- Kirk McDonald (11/19) May 31 2006 Ha! Why do you think I'm asking about this? Also note my earlier thread
- Tom S (63/80) May 31 2006 That's not necessary :>
- Oskar Linde (9/44) May 31 2006 I think you can manage this without needing to resort to autogenerated
- Bruno Medeiros (5/82) Jun 03 2006 Hum, pretty nice!
- Bruno Medeiros (19/59) Jun 03 2006 Just for the record, here's an alternative version, smaller, but less
- BCS (15/25) May 30 2006 I don't know if this is possible, however if it is and DMD stays true to...
By way of example, take this simple function template (taken from an example in the spec): template Foo(T, U=T*) { void Foo(T t) { U p; // ... } } int x; Foo(x); // T is int, U is int* Say I have a template function that takes a funtion pointer (or function object, I suppose) as an argument. template Bar(T) { void Bar(T t) { t(); } } void bar() { writef("Blah blah\n"); } Bar(&bar); Simple enough. But I want to deduce the return type of this function pointer, and make it the default value of a second template parameter. template Bar(T, U=<something>) { U Bar(T t) { return t(); } } Now, it's easy enough to explicitly instantiate this template, but I want to use this with the oh-so-useful implicit function template instantiation, so I could write e.g.: int bar() { return 7; } writef("value is: %d\n", Bar(&bar)); Is there something big and obvious stopping this that I'm not seeing? -Kirk McDonald
May 30 2006
Hey there :) I came up with this: ---- import std.stdio; template Deref(T) { alias typeof(*T) Deref; } template RetType(T) { static if (is(Deref!(T) U == function)) { alias U RetType; } else static assert (false); } template Bar(T, U=RetType!(T)) { U Bar(T t) { writefln(typeid(U)); // do something :P return U.init; } } cfloat func(int a, float b) { return 1.f + 0i; } void main() { writefln(Bar(&func)); } -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
May 30 2006
Ah! The IsExpression! I hadn't remembered that at all from when I read the spec. This will do nicely, thanks! -Kirk McDonald Tom S wrote:Hey there :) I came up with this: ---- import std.stdio; template Deref(T) { alias typeof(*T) Deref; } template RetType(T) { static if (is(Deref!(T) U == function)) { alias U RetType; } else static assert (false); } template Bar(T, U=RetType!(T)) { U Bar(T t) { writefln(typeid(U)); // do something :P return U.init; } } cfloat func(int a, float b) { return 1.f + 0i; } void main() { writefln(Bar(&func)); } -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
May 30 2006
Tom S wrote:Hey there :) I came up with this: ---- import std.stdio; template Deref(T) { alias typeof(*T) Deref; } template RetType(T) { static if (is(Deref!(T) U == function)) { alias U RetType; } else static assert (false); } template Bar(T, U=RetType!(T)) { U Bar(T t) { writefln(typeid(U)); // do something :P return U.init; } } cfloat func(int a, float b) { return 1.f + 0i; } void main() { writefln(Bar(&func)); } -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/Wow. That's... so much nicer than mine. I'm not even going to post my comparatively hideous solution :p May as well ask this: do you know a simple way to infer both the number and type of a function's arguments? I have a set of templates that can do this, but they're somewhat ugly. -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 30 2006
Daniel Keep wrote:May as well ask this: do you know a simple way to infer both the number and type of a function's arguments? I have a set of templates that can do this, but they're somewhat ugly. -- DanielIn C++, at least (which, yes yes, is not D, but it is similar enough in this respect), you had to do something like the following: template Foo(Fn) { void Foo(Fn fn) { fn(); } } template Foo(Fn, A0) { void Foo(Fn fn, A0 a0) { fn(a0); } } template Foo(Fn, A0, A1) { void Foo(Fn fn, A0 a0, A1 a1) { fn(a0, a1); } } // Ad absurdum, for as many args as you wish to support. Ugly, no? Try looking through the Boost::Tuple library sometime for the ultimate real-world example of this. (It supports this for up to 10 arguments.) What would totally nip this thing in the bud would be variadic templates, where something like this would work: template Foo(Fn, ...) { void Foo(Fn fn, ...) { fn(<pass_args_somehow>); } } I think I saw a post on this newsgroup somewhere where Walter said he'd like to see this in D... ah! Here's the quote: Walter Bright wrote on Feb 9, 2006:I know it'd be cool, and I want to do it. But it's a 2.0 thing.-Kirk McDonald
May 31 2006
Daniel Keep wrote:May as well ask this: do you know a simple way to infer both the number and type of a function's arguments? I have a set of templates that can do this, but they're somewhat ugly.Unfortunately I've got no idea as how to do it in a way that would detect more than primitive types as the arguments. My guess is that D would need more metainfo for functions or a means of converting a "type" to type (compile-time string to a compile-time identifier). -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
May 31 2006
Tom S wrote:Daniel Keep wrote:Actually, it's quite simple, if utterly evil. It involves abusing IFTI in the most gruesome manner imaginable... Detecting the number of arguments looks like this: What do you think of that sneaky use of typedefs? ^_^ Deducing the return type, and argument types is pretty similar (except instead of using ArglenN, you use Tr for the return type or Ta, Tb, Tc, etc for the argument types). The neat upshot of this is that despite using IFTI, I don't actually think those functions ever get instantiated; they certainly never run, which is kinda cool. Thankfully, I have a nifty little Python script that saves me having to actually *type* all that out. I give it a maximum number of arguments, and it goes off and generates the template for me. Evil was never so easy! I actually came up with this because I want to find a way to do Boost-style Python embedding. So you can just use PyWrap(someFn) to generate a Python wrapper for any old D function. *drools at the thought of D+Python* Oops *mops up puddle* -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/May as well ask this: do you know a simple way to infer both the number and type of a function's arguments? I have a set of templates that can do this, but they're somewhat ugly.Unfortunately I've got no idea as how to do it in a way that would detect more than primitive types as the arguments. My guess is that D would need more metainfo for functions or a means of converting a "type" to type (compile-time string to a compile-time identifier).
May 31 2006
Daniel Keep wrote:I actually came up with this because I want to find a way to do Boost-style Python embedding. So you can just use PyWrap(someFn) to generate a Python wrapper for any old D function. *drools at the thought of D+Python* Oops *mops up puddle* -- DanielHa! Why do you think I'm asking about this? Also note my earlier thread asking about the state of the Python/D API. I would love to see your code for PyWrap. I've got most of a wrapper around PyObject already. The biggest thing missing (beyond finishing wrapping Python's object interface, which is pretty trivial) is a translator between Python and D exceptions, which requires something like PyWrap to truly function (so it can catch any uncaught D exceptions and safely pass them back into Python). (Yes, this IS how Boost.Python does it, if you're wondering.) :-) -Kirk McDonald
May 31 2006
Daniel Keep wrote:Actually, it's quite simple, if utterly evil. It involves abusing IFTI in the most gruesome manner imaginable... Detecting the number of arguments looks like this: ( ... )Neat !! I didn't realize IFTI could do that :DWhat do you think of that sneaky use of typedefs? ^_^ Deducing the return type, and argument types is pretty similar (except instead of using ArglenN, you use Tr for the return type or Ta, Tb, Tc, etc for the argument types).That's not necessary :>The neat upshot of this is that despite using IFTI, I don't actually think those functions ever get instantiated; they certainly never run, which is kinda cool.AFAICS, they are instantiated, but never called so the linker or even the compiler might optimize them away :)Thankfully, I have a nifty little Python script that saves me having to actually *type* all that out. I give it a maximum number of arguments, and it goes off and generates the template for me. Evil was never so easy!Hehehe, I use it as well for other sorts of stuff, where I have to generate lots of such code that would be handled by variadic templates if we had them ;) How about taking it a step further and doing something like: ---- import std.stdio; struct FuncMeta(int NumArgs, Ret, T0=void, T1=void /+, and, so, on+/) { alias FuncMeta Meta; static const int numArgs = NumArgs; alias Ret RetType; alias T0 Arg0Type; // these might use static if as well alias T1 Arg1Type; /+ ... and so on +/ } template funcInfo(Ret) { FuncMeta!(0, Ret) funcInfo(Ret function() x) { assert(false); }; } template funcInfo(Ret, T0) { FuncMeta!(1, Ret, T0) funcInfo(Ret function(T0) x) { assert(false); }; } template funcInfo(Ret, T0, T1) { FuncMeta!(2, Ret, T0, T1) funcInfo(Ret function(T0, T1) x) { assert(false); }; } /+ ... template funcInfo(Ret, T0, T1, ..., Tn) { ... } +/ struct Foo {} void fooFunc(Foo a, float b) {} int barFunc(cfloat x) {} void main(char[][] args) { writefln("Number of args of main: ", funcInfo(&main).numArgs); writefln("\nfunc foo:"); alias typeof(funcInfo(&fooFunc)) FooMeta; writefln(FooMeta.numArgs); writefln(typeid(FooMeta.RetType)); writefln(typeid(FooMeta.Arg0Type)); writefln(typeid(FooMeta.Arg1Type)); writefln("\nfunc bar:"); alias typeof(funcInfo(&barFunc)) BarMeta; writefln(BarMeta.numArgs); writefln(typeid(BarMeta.RetType)); writefln(typeid(BarMeta.Arg0Type)); static if (BarMeta.numArgs >= 2) { writefln(typeid(BarMeta.Arg1Type)); } else { writefln("bar doesn't have Arg1Type"); } } Note that the ArgXType could be static if'fed away so one would get an error when trying to access them instead of having them alias to void. -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
May 31 2006
Tom S skrev:Daniel Keep wrote:I agree! But how can you call something this beautiful evil? :)Actually, it's quite simple, if utterly evil. It involves abusing IFTI in the most gruesome manner imaginable... Detecting the number of arguments looks like this: ( ... )Neat !! I didn't realize IFTI could do that :DI think you can manage this without needing to resort to autogenerated code by using a generic variadic template list generator. There will still be a hard-coded limit in the maximum number of function arguments though.Thankfully, I have a nifty little Python script that saves me having to actually *type* all that out. I give it a maximum number of arguments, and it goes off and generates the template for me. Evil was never so easy!Hehehe, I use it as well for other sorts of stuff, where I have to generate lots of such code that would be handled by variadic templates if we had them ;)How about taking it a step further and doing something like: ---- import std.stdio; struct FuncMeta(int NumArgs, Ret, T0=void, T1=void /+, and, so, on+/) { alias FuncMeta Meta; static const int numArgs = NumArgs; alias Ret RetType; alias T0 Arg0Type; // these might use static if as well alias T1 Arg1Type; /+ ... and so on +/ }[snip the rest] Marvelous! this will be very useful for me in a number of places. /Oskar
May 31 2006
Tom S wrote:How about taking it a step further and doing something like: ---- import std.stdio; struct FuncMeta(int NumArgs, Ret, T0=void, T1=void /+, and, so, on+/) { alias FuncMeta Meta; static const int numArgs = NumArgs; alias Ret RetType; alias T0 Arg0Type; // these might use static if as well alias T1 Arg1Type; /+ ... and so on +/ } template funcInfo(Ret) { FuncMeta!(0, Ret) funcInfo(Ret function() x) { assert(false); }; } template funcInfo(Ret, T0) { FuncMeta!(1, Ret, T0) funcInfo(Ret function(T0) x) { assert(false); }; } template funcInfo(Ret, T0, T1) { FuncMeta!(2, Ret, T0, T1) funcInfo(Ret function(T0, T1) x) { assert(false); }; } /+ .... template funcInfo(Ret, T0, T1, ..., Tn) { ... } +/ struct Foo {} void fooFunc(Foo a, float b) {} int barFunc(cfloat x) {} void main(char[][] args) { writefln("Number of args of main: ", funcInfo(&main).numArgs); writefln("\nfunc foo:"); alias typeof(funcInfo(&fooFunc)) FooMeta; writefln(FooMeta.numArgs); writefln(typeid(FooMeta.RetType)); writefln(typeid(FooMeta.Arg0Type)); writefln(typeid(FooMeta.Arg1Type)); writefln("\nfunc bar:"); alias typeof(funcInfo(&barFunc)) BarMeta; writefln(BarMeta.numArgs); writefln(typeid(BarMeta.RetType)); writefln(typeid(BarMeta.Arg0Type)); static if (BarMeta.numArgs >= 2) { writefln(typeid(BarMeta.Arg1Type)); } else { writefln("bar doesn't have Arg1Type"); } } Note that the ArgXType could be static if'fed away so one would get an error when trying to access them instead of having them alias to void.Hum, pretty nice! -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Jun 03 2006
Tom S wrote:Hey there :) I came up with this: ---- import std.stdio; template Deref(T) { alias typeof(*T) Deref; } template RetType(T) { static if (is(Deref!(T) U == function)) { alias U RetType; } else static assert (false); } template Bar(T, U=RetType!(T)) { U Bar(T t) { writefln(typeid(U)); // do something :P return U.init; } } cfloat func(int a, float b) { return 1.f + 0i; } void main() { writefln(Bar(&func)); } -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/Just for the record, here's an alternative version, smaller, but less flexible(because you must know the parameters of the T function, and you have worse error messages): template Bar(T, U = typeof(T(0,0)) ) { U Bar(T t) { writefln(typeid(U)); return U.init; } } cfloat func(int a, float b) { return 1.f + 0i; } void main() { writefln(Bar(&func)); } -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Jun 03 2006
Kirk McDonald wrote: [...]Simple enough. But I want to deduce the return type of this function pointer, and make it the default value of a second template parameter. template Bar(T, U=<something>) { U Bar(T t) { return t(); } }I don't know if this is possible, however if it is and DMD stays true to form it will have a oddity, consider template Bar(T, U=<something>) { U Bar(T t) { return t(1.234567789); } float foo(float i) { return i; } double foo(double i) { return cast(float)i; } real foo(real i) { return cast(float)i; } Bar(foo); // which foo, which return type? as it stand the first foo encountered will be used (lexical order changes meaning in this case).
May 30 2006