Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store std::complex operator as a variable (C++)

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+=;
like image 829
CuriousSoul Avatar asked Oct 24 '25 06:10

CuriousSoul


2 Answers

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>&.

like image 131
463035818_is_not_a_number Avatar answered Oct 26 '25 19:10

463035818_is_not_a_number


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.

like image 39
Red.Wave Avatar answered Oct 26 '25 19:10

Red.Wave



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!