How to store std::sqrt in std::function

Viewed 167

std::sqrt() is of type std::complex<T>(const std::complex<T>&). Why can't I store it in this std::function? The error I get is:

error: conversion from ‘’ to non-scalar type ‘std::function(const std::complex&)>’ requested

Run it here:

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

int main(){
    using Complex = std::complex<double>;
    std::function<Complex(const Complex&)> f = std::sqrt;
    std::cout << "sqrt(4): " << f(std::complex<double>(4,0)) << "\n";
    return 0;
}
2 Answers

Concerning the line in your code:

std::function<Complex(const Complex&)> f = std::sqrt;

You must take into account that std::sqrt() is not an ordinary function but a function template:

template<class T>
complex<T> sqrt(const complex<T>& z);

You defined Complex in terms of the std::complex class template:

using Complex = std::complex<double>;

Since std::complex contains the member type value_type that corresponds to the passed template argument (i.e., double in this case), you can just do:

std::function<Complex(const Complex&)> f = std::sqrt<Complex::value_type>;

This is equivalent to directly passing double as template argument to std::sqrt():

std::function<Complex(const Complex&)> f = std::sqrt<double>;

However, the former is more generic than the latter because it allows you to change std::complex's template argument – e.g., using int or float instead of double – without having to edit the source code corresponding to the assignment.


Since C++14 you can also wrap the call to std::sqrt() by means of a generic lambda and assign this lambda to the std::function object:

std::function<Complex(const Complex&)> f = [](auto const& x) { 
   return std::sqrt(x); 
};

You just forgot the template parameter for the assignment.

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

int main(){
    using Complex = std::complex<double>;
    std::function<Complex(const Complex&)> f = std::sqrt<double>;
    std::cout << "sqrt(4): " << f(std::complex<double>(4,0)) << "\n";
    return 0;
}
Related