patterncppMinor
Most elegant variadic functor
Viewed 0 times
elegantfunctorvariadicmost
Problem
Question
Suppose we have two sorts of classes
Given an output class and several input classes (arbitrary number),
consider the following procedure:
This procedure can be seen as a call to a function taking the input's
values as arguments an returning the output value.
Write the functor that constructs such a variadic function in the general case.
Constraints are: C++ (most likely C++11), arbitrary number of input
classes of possibly different
big bonus if the code is elegant and readable.
Details: For those who wonder how
as well, which returns whatever you provided via
then has a constructor that takes various
(or their reference) as member variables.
some math by using the return values of its input's
and returns some result of type
Proposed solution
The
Suppose we have two sorts of classes
- an input class
Input
- defines a type
result_type
- defines
set(result_type)
- an output class
Output
- defines a type
result_type
- defines
result_type get() const
- has a number of
Inputclasses as member variables, on which its output depends
Given an output class and several input classes (arbitrary number),
consider the following procedure:
- loop over each input class and call
set()with an appropriate value (defined beforehand)
- call the
get()on the ouput class and collect the result.
This procedure can be seen as a call to a function taking the input's
values as arguments an returning the output value.
Write the functor that constructs such a variadic function in the general case.
Constraints are: C++ (most likely C++11), arbitrary number of input
classes of possibly different
Input::result_types. Note thatInput::result_type is not necessarily related toOutput::result_type. Aim should first be efficiency, but there's abig bonus if the code is elegant and readable.
Details: For those who wonder how
Output is related to Input, one could imagine that Input has a result_type get() const methodas well, which returns whatever you provided via
set(). Outputthen has a constructor that takes various
Inputs, and stores them(or their reference) as member variables.
Output::get() then doessome math by using the return values of its input's
get() methods,and returns some result of type
Output::result_type.Proposed solution
#include
template
std::function
make_function(const Output& output, Inputs&... inputs) {
return[&](typename Inputs::result_type... input_vals) {
int dummy[]{0, (inputs.set(input_vals),0)...};
return output.get();
};
}The
int dummy[] line is due to @ecatmur's answer.Solution
Looks to me as if you've already got the most elegant solution in mind.
In C++14 you'd remove the dependency on
but in C++11 you can't make a function-that-returns-a-naked-lambda without a ton of boilerplate — if it's even possible at all.
Also, a nitpick, with props to @stephan-t-lavavej's talk at CppCon 2014. You wrote
but what you should have written was
to avoid accidentally calling
In C++14 you'd remove the dependency on
std::function and simply return a naked lambda, like this:template
auto make_function(const Output& output, Inputs&... inputs) {
return [&](typename Inputs::result_type... input_vals) {
int dummy[] { 0, ((void)inputs.set(input_vals),0)... };
return output.get();
};
}but in C++11 you can't make a function-that-returns-a-naked-lambda without a ton of boilerplate — if it's even possible at all.
Also, a nitpick, with props to @stephan-t-lavavej's talk at CppCon 2014. You wrote
(inputs.set(input_vals),0)...but what you should have written was
((void)inputs.set(input_vals),0)...to avoid accidentally calling
MaliciousUserCode::operator,(int).Code Snippets
template <class Output, class... Inputs>
auto make_function(const Output& output, Inputs&... inputs) {
return [&](typename Inputs::result_type... input_vals) {
int dummy[] { 0, ((void)inputs.set(input_vals),0)... };
return output.get();
};
}(inputs.set(input_vals),0)...((void)inputs.set(input_vals),0)...Context
StackExchange Code Review Q#39750, answer score: 2
Revisions (0)
No revisions yet.