2

I have a function with signature:

template<class Type> 
bool isPrime(const Type& n,float (*fSqrt)(float),bool debug = false)

Which works fine. But,

template<class Type> 
bool isPrime(const Type& n,std::function<float(float)> fSqrt,bool debug = false)

causes compile-error.

How to replace float (*fSqrt)(float) with std::function<float(float)> fSqrt ?
Please note: my ultimate objective is std::function<float(Type)>, where Type is templated.

Wandbox (https://wandbox.org/) shows:

prog.cc: In function 'int main()':
prog.cc:91:28: error: no matching function for call to 'isPrime(int&, <unresolved overloaded function type>, bool)'
   91 |         std::cout<<(isPrime(n,std::sqrt,true)?"Positive":"Negative")<<'\n';
      |                     ~~~~~~~^~~~~~~~~~~~~~~~~~
prog.cc:10:27: note: candidate: 'template<class Type> bool isPrime(const Type&, const float&, bool)'
   10 | template<class Type> bool isPrime(const Type& n,const float& nSqrt = 0.0,bool debug = false) {
      |                           ^~~~~~~
prog.cc:10:27: note:   template argument deduction/substitution failed:
prog.cc:91:28: note:   cannot convert 'std::sqrt' (type '<unresolved overloaded function type>') to type 'const float&'
   91 |         std::cout<<(isPrime(n,std::sqrt,true)?"Positive":"Negative")<<'\n';
      |                     ~~~~~~~^~~~~~~~~~~~~~~~~~
prog.cc:81:27: note: candidate: 'template<class Type> bool isPrime(const Type&, std::function<float(float)>, bool)'
   81 | template<class Type> bool isPrime(const Type& n,std::function<float(float)> fSqrt,bool debug = false) {    // Type & std::function - compile-error
      |                           ^~~~~~~
prog.cc:81:27: note:   template argument deduction/substitution failed:
prog.cc:91:28: note:   cannot convert 'std::sqrt' (type '<unresolved overloaded function type>') to type 'std::function<float(float)>'
   91 |         std::cout<<(isPrime(n,std::sqrt,true)?"Positive":"Negative")<<'\n';
      |                     ~~~~~~~^~~~~~~~~~~~~~~~~~

OnlineGDB (https://www.onlinegdb.com/#) shows:

main.cpp:91:38: error: no matching function for call to ‘isPrime(int&, , bool)’
  std::cout<<(isPrime(n,std::sqrt,true)?"Positive":"Negative")<<'\n';
                                      ^
main.cpp:10:27: note: candidate: template bool isPrime(const Type&, const float&, bool)
 template<class Type> bool isPrime(const Type& n,const float& nSqrt = 0.0,bool debug = false) {
                           ^~~~~~~
main.cpp:10:27: note:   template argument deduction/substitution failed:
main.cpp:91:38: note:   cannot convert ‘sqrt’ (type ‘’) to type ‘const float&’
  std::cout<<(isPrime(n,std::sqrt,true)?"Positive":"Negative")<<'\n';
                                      ^
main.cpp:81:27: note: candidate: template bool isPrime(const Type&, std::function, bool)
 template<class Type> bool isPrime(const Type& n,std::function<float(float)> fSqrt,bool debug = false) {    // Type & std::function - compile-error
                           ^~~~~~~
main.cpp:81:27: note:   template argument deduction/substitution failed:
main.cpp:91:38: note:   cannot convert ‘sqrt’ (type ‘’) to type ‘std::function’
  std::cout<<(isPrime(n,std::sqrt,true)?"Positive":"Negative")<<'\n';
                                      ^
JeJo
  • 30,635
  • 6
  • 49
  • 88
Supreeto
  • 198
  • 9

1 Answers1

3

As others have pointed out std::sqrt has multiple overload, and you should specify which one to deduce there to be a std:.function. For example static_cast<float(*)(float)>(std::sqrt).

However, you should not be taking the address of a standard library function. See in detail here: Can I take the address of a function defined in standard library?

Secondly the std::function comes with a type-erasure overhead.

Therefore, I suggest packing the std::sqrt to a lambda, and use template argument to deduce the lambda by the compiler. Something like

template<class Type, typename Callable> 
bool isPrime(const Type& n, Callable fSqrt, bool debug = false)
{
    // ...
}

and call via

isPrime(2.f, [](float val) { return std::sqrt(val); });

However, now isPrime takes anything callable. This can be restricted only for the specific one by sfinaeing the function.

#include <type_traits> // std::enable_if, std::is_floating, std::invoke_result

template<class Type, typename Callable> 
auto isPrime(const Type& n, Callable fSqrt, bool debug = false)
->std::enable_if_t<std::is_floating_point_v<std::invoke_result_t<Callable, Type>>, bool>
{
    // ...
}
JeJo
  • 30,635
  • 6
  • 49
  • 88
  • Thanks @JeJo. [1.] Already got `static_assert (std::is_integral::value,"ERR: integral type required");` in place. [2.] Why can't the compiler deduce this `static_cast(std::sqrt)` ? – Supreeto Oct 21 '21 at 07:34