Understanding Safety of Function Pointers vs. Addresses of Functions

anonymous via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Jul 12 10:11:02 PDT 2015


On Sunday, 12 July 2015 at 16:34:17 UTC, jmh530 wrote:
> I've been playing around with this a little more. I wrote this 
> function to encapsulate a simple operation on arrays.
>
> U array_fun(T, U)(T fp, U x)
> 	if (isFunctionPointer!(T) && isArray!(U))
> {
> 	return x.map!(a => fp(a)).array;
> }
>
> Then I wrote a cos function that calls it on using a function 
> pointer.
>
> T cos(T : U[], U)(T x)
> 	if (isArray!(T))
> {
> 	auto fp = (U a) => cos(a);
> 	return array_fun(fp, x);
> }
>
> This seems to work just fine, but for some reason this only 
> seems to work when I import std.math : cos. It doesn't work 
> when I just do import std.math. Bug?

Your function is called cos, too. So you need your local cos and 
std.math.cos to form an overload set. This isn't automatically 
done with implicitly imported functions to avoid hijacking [1] 
(accidentally calling the wrong function). Selectively imported 
functions are added to the overload set, as you (the programmer) 
are obviously aware of them and want them in the overload set. An 
alternative would be to use an alias:
----
import std.math;
alias cos = std.math.cos;
----

> Nevertheless, if I want to implement it for another function, 
> then I have to write it all over again. So I wrote a mixin that 
> would encapsulate that idea (I put in the \n, \t for formatting 
> purposes because I like to be able to writeln it out and see 
> that it matches the original).
>
> template mixin_builder(string function_name)
> {
> 	const char[] mixin_builder =
> 		"T " ~ function_name ~ "(T : U[], U)(T x)\n" ~
> 			"\tif (isArray!(T))\n" ~
> 		"{\n" ~
> 			"\tauto fp = (U a) => " ~ function_name ~ "(a);\n" ~
> 			"\treturn array_fun(fp, x);\n" ~
> 		"}";
> }
>
> Then I can just call
> mixin(mixin_builder!("cos"));
> mixin(mixin_builder!("sin"));
>
> While it works, it feels a bit hackish. I'm not sure I can 
> think of a generic way to do this without mixins.

Take the function via an alias parameter:
----
template givemeabettername(alias fun)
{
     T givemeabettername(T : U[], U)(T x)
         if (isArray!(T))
     {
         auto fp = (U a) => fun(a);
         return array_fun(fp, x);
     }
}
alias cos = givemeabettername!(std.math.cos);
alias sin = givemeabettername!(std.math.sin);
----

But turning a statically known function to a function pointer 
only to pass it to `map` seems pointless to me. So:
----
template givemeabettername(alias fun)
{
     T givemeabettername(T : U[], U)(T x)
         if (isArray!(T)) /* With the specialization above, this 
is redundant, isn't it?  */
     {
         return x.map!fun.array;
     }
}
----

And personally, I'd probably just type out `x.map!fun.array` 
every time.

[1] http://dlang.org/hijack.html


More information about the Digitalmars-d-learn mailing list