0

Check it out at godbolt

#include <complex>
#include <functional>
#include <iostream>
#include <vector>

using Complex = std::complex<double>;

using namespace std::literals::complex_literals;

struct S
{
    std::vector<Complex> data;
    S& apply(std::function<Complex(Complex const&)> f)
    {
        for( auto& elem : data )
        {
            elem = f(elem);
        }
        return *this;
    }
};

int main()
{
    S s{{1.i,-2.i,3.i}};
    s.apply(std::conj); // error 
    return EXIT_SUCCESS;
}

error: cannot convert '<unresolved overloaded function type>' to 'std::function<std::complex<double>(const std::complex<double>&)>'

Now a single workaround would be to use a lambda or define a non-templated function. Is there another way how I can specify the template so I can pass std::conj to std::function ?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
infinitezero
  • 1,610
  • 3
  • 14
  • 29

2 Answers2

3

You may overload for regular function pointers.

struct S
{
    std::vector<Complex> data;
    using CB = Complex(Complex const&);
    S& apply(std::function<CB> f)
    {
        for( auto& elem : data )
        {
            elem = f(elem);
        }
        return *this;
    }
    S& apply(CB* cb) { return apply(std::function(cb)); }
};

std::function accepts via its constructor template. So an overload set cannot be resolved by it. But a regular function pointer can delineate an overload set by deducing against its concrete type.

There's a caveat though. The standard doesn't generally allow taking the addresses of standard library functions (or specializations) unless they are explicitly marked as "addressable functions". That's how it future proofs itself so that overloads may be added in future revisions without breaking existing code that follows the contract.

A lambda is usually advised for this reason alone.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
1

std::conj() is an overloaded function. You have to specify which overload you actually want when passing std::conj to your function, eg:

s.apply(static_cast<Complex (*)(const Complex&)>(std::conj));

Online Demo

Alternatively:

Complex (*func)(const Complex&) = std::conj;
s.apply(func);

Online Demo

Also see Address of an overloaded function on cppreference.com

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770