infinitezero
infinitezero

Reputation: 2077

Can't use complex C++ functions in std::function #2

Previous question

For reasons unknown to me, my code stopped working today. For preimplemented functions I have a relay code like this

Math_Node& Function_Manager::relay_complex_to_std(Math_Node& arg, std::function<Complex(const Complex&)> f) const{
    if( arg.children_.size() != 1 ){
        throw std::runtime_error("Function expects exactly one argument.");
    }
    evaluate(*arg.children_[0]);
    if( std::holds_alternative<Complex>(arg.children_[0]->data_) ){
        arg.data_ = f(std::get<Complex>(arg.children_[0]->data_));
        arg.children_.clear();
    }
    return arg;
}

with the types

using Decimal       = double;
using Complex       = std::complex<Decimal>;

This can be called by a different function like

Math_Node& Function_Manager::sqrt(Math_Node& arg) const{
    //return relay_complex_to_std(arg, std::sqrt<Complex::value_type>);
    return relay_complex_to_std(arg, [](Complex a){return std::sqrt(a);});
}

The commented line stopped working with the error message

In member function ‘Numeric_Calculator::Math_Node& Numeric_Calculator::Function_Manager::sqrt(Numeric_Calculator::Math_Node&) const’:
functionmanager.cpp:214:72: error: 
no matching function for call to ‘Numeric_Calculator::Function_Manager::relay_complex_to_std(Numeric_Calculator::Math_Node&, unresolved overloaded function type>) const’
         return relay_complex_to_std(arg, std::sqrt<Complex::value_type>);

Why is the function type not resolved? It works when I put it in a lambda.

Compiler:

g++-9 --version
g++-9 (Ubuntu 9.2.1-17ubuntu1~18.04.1) 9.2.1 20191102

edit:

Thanks to Jarod42 for pointing out the overload with valarray. You can see for yourself that de-commenting the below line will result in the same error

#include <cmath>
#include <complex>
#include <functional>
#include <iostream>
//#include <valarray>

using Complex = std::complex<double>;

Complex relay(Complex arg, std::function<Complex(Complex)> f){
    return f(arg);
}

int main(){
    std::function<Complex(Complex)> f = std::sqrt<Complex::value_type>;
    std::cout << std::sqrt(4.0) << "\n";
    std::cout << relay(Complex(-2,0), std::sqrt<Complex::value_type>) << "\n";
    return 0;
}

Upvotes: 0

Views: 87

Answers (1)

Jarod42
Jarod42

Reputation: 217438

std::sqrt<double> might be ambiguous, it might be

And whereas std::complex one might be converted to the expected std::function, name resolution doesn't take that conversion into account.

See Address of an overloaded function for more details.

Upvotes: 1

Related Questions