admin管理员组

文章数量:1410717

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+=;

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+=;
Share edited Mar 5 at 18:03 Remy Lebeau 601k36 gold badges508 silver badges851 bronze badges asked Mar 5 at 17:01 CuriousSoulCuriousSoul 432 bronze badges 3
  • You might use lambda, which avoid issue with overload: std::function<void(std::complex<double>&, const std::complex<double>&)> var = [](td::complex<double>& lhs, const std::complex<double>& rhs){ lhs += rhs; }; – Jarod42 Commented Mar 5 at 17:02
  • operator += returns self BTW, and then it is trickier with lambda. you have to specify the return type, or decltype(auto) with appropriate expression. – Jarod42 Commented Mar 5 at 17:07
  • Are you looking for something like named operations, such as std::plus? (Depending on your operations, you may need to roll some of your own. Only some of the operators are provided this way, and I think that none of the "in place" (assigning) operators are provided.) – Eljay Commented Mar 5 at 17:15
Add a comment  | 

3 Answers 3

Reset to default 4

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.

You should check the documentation of std::complex::operator+=.

Note the template version has only one overload:

constexpr complex& operator+=( const T& other ); // (1)

which does not match your case (you are expecting argument type const std::complex<T>&).

Now, if you take a look lower in the doc, you will see another template version of operator+=:

template<class X>
constexpr complex& operator+=( const std::complex<X>& other ); // (5)

So you need this to make it work:

std::function<void(std::complex<double>&, const std::complex<double>&)> var = 
                                               &std::complex<double>::operator+=<double>;

Note the extra <double>!

https://godbolt./z/TPGMe435s

Note that this operator should also work when adding std::complex with different base types, that is why the template of member function is needed, so std::complex<float> and std::complex<double> could be added.

本文标签: functionHow to store stdcomplex operator as a variable (C)Stack Overflow