Difference between revisions of "Compile-time Command Pattern"
m |
|||
Line 44: | Line 44: | ||
A lambda function that multiplies two numbers together is used as an example. This is actually a template literal because the types of <code>a</code> and <code>b</code> are not specified. | A lambda function that multiplies two numbers together is used as an example. This is actually a template literal because the types of <code>a</code> and <code>b</code> are not specified. | ||
+ | |||
+ | [[Category:DesignPattern]] |
Latest revision as of 10:19, 14 November 2014
From David Simcha's D-Specific Design Patterns talk at DConf 2013.
Problem: Need to store function and arguments to be invoked later
Want:
- Variadic argument list
- Inlineability
- Return type polymorphism
- Ability to store uninstantiated function templates
- Minimal boilerplate
Solution: Tempate alias
+ variadic templates
struct Command(alias fun, Args...)
{
Args args_;
auto invoke()
{
return fun(args_);
}
}
// Instantiator Function
auto command(alias fun, Args...)(Args args)
{
return Command!(fun, Args)(args);
}
void main()
{
auto cmd = command!((a, b) => a * b)(3, 2);
assert(cmd.invoke() == 6);
}
Command
struct takes an alias
for the function and a set of variadic arguments. An alias can be any compile-time symbol including an uninstantiated template.
The invoke
function is not virtual because you can't have virtual functions in structs in D, so it's inlinable, and it simply forwards to the function that's passed in at compile-time as an alias with the arguments.
Since everything is bound at compile-time, invoke
is inlinable and the function it forwards to in inlineable, there should be no overhead.
An instantiator function is used to avoid explicitly specifying all the arguments when instantiating cmd
.
A lambda function that multiplies two numbers together is used as an example. This is actually a template literal because the types of a
and b
are not specified.