I've been writing some tests for the arithmetic of complex numbers.
I've tried to write them in a way where I don't have to rewrite a code section for each operator. I am trying to store std::complex overloaded operators such as operator+, operator+=, operator-, operator-= in a std::function variable. The reason why I need the std::complex operators is because I need to check them against my own implementation of complex numbers.
However, I can't get it to work, mostly because there seems to be a mismatch between the type of the variable (std::function) and the type of the value (std::complex operators). How should I write the code so that I can store these operator functions in a std::function variable?
This is my attempt, but alas it doesn't work:
std::function<void(std::complex<double>&, const std::complex<double>&)> var =
&std::complex<double>::operator+=;
Use a lambda expression:
std::function<void(std::complex<double>&, const std::complex<double>&)> var =
[](std::complex<double>& a,const std::complex<double>& b) {
a+=b;
};
Note that operator+= does not return void. To keep the semantics of += change the lambda to return a+=b; and specify its return type to be std::complex<double>&.
Using <functional> there are generic function objects for almost all C++ operators, ecxept assignment and its compound counterparts, addressof and dereference and index:
#include <functional>
#include <complex>
using complex_f = std::complex<float>;
using fn_t =
std::function<void(complex_f&, complex_f const&)>;
fn_t add_fn = std::plus<>{};
fn_t multiply_fn = std::multiplies<>{};
However for operators with missing std classes, you need use lambdas:
auto constexpr add_assign =
[](auto& dst, auto const& src)
->decltype(auto)
{ return dst += src; };
fn_t increase_fn = add_assign;
functions and member functions defined in standard library and its classes have unspecified types. They just bear the name of function, and should not be assumed to be strictly functions. As such, trying to store their addresses as old-school function pointers is UB.
In my last snippet, I first defined a named generic lambda, then initialize an std::function with that lambda. This makes it possible to reliably compare instances of std::function using its target member template function:
auto const fn_tgt
= increase_fn.target<decltype(add_assign)>);
assert((nullptr!=fn_tgt);
If an unnamed lambda were used, such test wouldn't be available. Because every lambda instance has a unique distinct type identifier.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With