Present signature is
template<class TypeData,typename TypeFunc>
bool isPrime(const TypeData& n,TypeFunc fSqrt,bool debug = false)
and this works perfectly with
std::cout<<(isPrime(n,fSqrt)?"Positive":"Negative")<<'\n';
But, my intension is something like
template<class TypeData,typename TypeFunc>
bool isPrime(const TypeData& n,TypeFunc fSqrt = nullptr,bool debug = false)
or
template<class TypeData,typename TypeFunc>
bool isPrime(const TypeData& n,TypeFunc fSqrt = NULL,bool debug = false)
to be called by
std::cout<<(isPrime(n)?"Positive":"Negative")<<'\n';
Overloading is not possible due to a static variable inside the function.
Only different class TypeData
should give different template-functions for this function-template.
Please help me out with the proper syntax.
In case C does not support this, kindly advice me with alternative approaches.
Thank you.
Compile Errors
for TypeFunc fSqrt = nullptr
main.cpp:90:23: error: no matching function for call to ‘isPrime(int&)’
std::cout<<(isPrime(n)?"Positive":"Negative")<<'\n';
^
main.cpp:9:49: note: candidate: template bool isPrime(const TypeDate&, TypeFunc, bool)
template<class TypeDate,typename TypeFunc> bool isPrime(const TypeDate& n,TypeFunc fSqrt = nullptr,bool debug = false) {
^~~~~~~
main.cpp:9:49: note: template argument deduction/substitution failed:
main.cpp:90:23: note: couldn't deduce template parameter ‘TypeFunc’
std::cout<<(isPrime(n)?"Positive":"Negative")<<'\n';
^
for TypeFunc fSqrt = NULL
main.cpp:90:23: error: no matching function for call to ‘isPrime(int&)’
std::cout<<(isPrime(n)?"Positive":"Negative")<<'\n';
^
main.cpp:9:49: note: candidate: template bool isPrime(const TypeDate&, TypeFunc, bool)
template<class TypeDate,typename TypeFunc> bool isPrime(const TypeDate& n,TypeFunc fSqrt = NULL,bool debug = false) {
^~~~~~~
main.cpp:9:49: note: template argument deduction/substitution failed:
main.cpp:90:23: note: couldn't deduce template parameter ‘TypeFunc’
std::cout<<(isPrime(n)?"Positive":"Negative")<<'\n';
^
They are basically the same.
CodePudding user response:
You can use a default initialized std::function
with the correct prototype for that:
template<class TypeData>
bool isPrime(const TypeData& n,std::function<const decltype(n)&(const decltype(n)&)> fSqrt={},bool debug = false)
You can then check in the function if it is valid or the default one by simply if (fSqrt)
full example: https://godbolt.org/z/zfMazebso
The prototype must be dependent only on the datatype of n
, otherwise there is no default parameter possible, e.g., the compiler cannot deduce a type out of nothing.
CodePudding user response:
You can use std::identity
as the default TypeFunc
type.
#include <functional>
template<class TypeData,typename TypeFunc = std::identity>
bool isPrime(const TypeData& n,TypeFunc fSqrt = {}, bool debug = false) {
if constexpr (std::is_same_v<TypeFunc, std::identity>) return false;
else {
// ...
}
}
CodePudding user response:
Overloading actually is an option, you can let one overload call the other one:
template<class TypeData, typename TypeFunc>
bool isPrime(const TypeData& n, TypeFunc fSqrt, bool debug = false);
template<class TypeData>
bool isPrime(const TypeData& n, bool debug = false)
{
using std::sqrt;
if constexpr (std::is_integral_v<TypeData>)
{
return isPrime(n, static_cast<double(*)(double)>(sqrt), debug);
}
else if constexpr (std::is_floating_point_v<TypeData>)
{
return isPrime(n, static_cast<TypeData(*)(TypeData)>(sqrt), debug);
}
else
{
// this covers e.g. std::complex
return isPrime(n, static_cast<TypeData(*)(TypeData const&)>(sqrt), debug);
// for any other type we assume the overload accepts by
// const reference as well (if there's one at all...)
// if not, we still can fall back to the other overload
}
}
This solution selects an appropriate square root function right away, something you would have had to solve anyway if the function argument had defaulted to nullptr
.