Agreed.
> C++11 added support that means the input structure can be specified
> inline, as in the call `func_foo::exec({1, 2, 3})`.
Indeed. FWIW, sometimes I like to create the "input" structure ahead of
time, especially if it has many "parameters". Another contrived reason
is the ability to reuse a similar "template like" input structure cast
over many calls to (::result_for(i)) in the same scope.
> C++17 adds support for returning multiple values from a function, here's
> an example from ¹a Stack Overflow Q/A:
>
>
> [code]
> #include <tuple>
>
> using namespace std;
>
> tuple<int, int> divide(int dividend, int divisor) {
> return {dividend / divisor, dividend % divisor};
> }
>
> #include <iostream>
>
> int main() {
> auto [quotient, remainder] = divide(14, 3);
>
> cout << quotient << ',' << remainder << endl;
> }
> [/code]
This looks very nice, however, imvvho this seems like a bit of a
"different" language to me. I understand auto, but personally still like
a type name in the source code:
___________________________
auto i0 = 123.0;
auto i1 = 123.0f;
vs:
double i0 = 123.0;
float i1 = 123.0f;
___________________________
Ahh, perhaps I need to brush up on my modern C++ skills!
;^o
FWIW, here is a little example of where I might want to use the input
output binding type thing. Here is a function that can find cycles in
the Mandelbrot set. It uses a slow and fast iteration "pointer",
basically identical to finding cycles in linked lists.
Here is the crude code using the "free-function" input/output
encapsulation "thing":
_____________________________________________
#include <complex>
#include <cstdio>
typedef double ct_float;
typedef std::complex<ct_float> ct_complex;
bool
ct_complex_compare(
ct_complex const& c0,
ct_complex c1,
ct_float epsilon
) {
ct_complex d = c1 - c0;
return std::abs(d) < epsilon;
}
struct mbrot_detect_cycle
{
struct input
{
ct_complex c;
ct_complex z;
ct_float escape;
ct_float epsilon;
unsigned int imax;
};
struct output
{
ct_complex z;
unsigned int i;
bool cycle;
};
static output result_for(input const& in)
{
ct_complex slow = in.z;
ct_complex fast = in.z;
for (unsigned int i = 0; i < in.imax; ++i)
{
slow = slow*slow + in.c;
fast = fast*fast + in.c;
fast = fast*fast + in.c;
if (ct_complex_compare(slow, fast, in.epsilon))
{
return{ slow, i, true };
}
ct_float dis = std::abs(slow);
if (dis > in.escape)
{
return{ slow, i, false };
}
// uncomment following line for progress meter... ;^)
//if (! (i % 10000)) std::printf("i:%u\r", i);
}
return{ slow, in.imax, false };
}
};
int main()
{
{
mbrot_detect_cycle::input in = {
// fine grain epsilon takes many iterations
// for this point (-.75, 0):
{ -.75, 0 },
{ 0, 0 },
2,
.0001,
500000000
};
mbrot_detect_cycle::output out =
mbrot_detect_cycle::result_for(in);
if (out.cycle)
{
std::printf(
"cycle found for in.c:(%f, %f) "
"at out.i:(%u) iterations in.epsilon:(%f)\n",
in.c.real(), in.c.imag(), out.i, in.epsilon);
}
else
{
std::printf(
"** NO ** cycle was found for in.c:(%f, %f) "
"at out.i:(%u) iterations in.epsilon:(%f)\n",
in.c.real(), in.c.imag(), out.i, in.epsilon);
}
}
return 0;
}
_____________________________________________
FWIW, one can try using different points to test. FWIW, I get the
following output for this code:
_____________________________________________
cycle found for in.c:(-0.750000, 0.000000) at out.i:(4291771) iterations
in.epsilon:(0.000100)
_____________________________________________