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. If C++ does not support this, what is an alternative approach I can use?
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.
Default argument cannot be provided for pointers to functions.
Of the operators, only the function call operator and the operator new can have default arguments when they are overloaded. You can supply any default argument values in the function declaration or in the definition.
There are no default parameters in C. One way you can get by this is to pass in NULL pointers and then set the values to the default if NULL is passed.
Default arguments are only allowed in the parameter lists of function declarations and lambda-expressions, (since C++11) and are not allowed in the declarations of pointers to functions, references to functions, or in typedef declarations.
void pointer in C. The void pointer in C is a pointer which is not associated with any data types. It points to some data location in the storage means points to the address of variables.
From C11 standard clause 6.3.2.3, “ An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function. ”
Pointer is null after returning from function call 0 Roots of cubic using C and GSL 0 C function with data structure pointer parameter Related 3612 What are the differences between a pointer variable and a reference variable in C++?
1) Pointer arithmetic is not possible with void pointer due to its concrete size. 2) It can’t be used as dereferenced. Begin Declare a of the integer datatype. Initialize a = 7.
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 {
// ...
}
}
Demo.
If your compiler does not support C++20, you can just simply define your own std::identity
:
struct Identity {
template<class T>
constexpr decltype(auto) operator()(T&& t) const noexcept {
return std::forward<T>(t);
}
};
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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With