Search code examples
c++functionc++11templatesfunction-pointers

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


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;
}

Solution

  • 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); 
    };