Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add void/null as default argument to a function/lambda pointer, in C++?

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.

like image 703
Supreeto Avatar asked Oct 21 '21 13:10

Supreeto


People also ask

CAN default arguments be provided for pointers to functions?

Default argument cannot be provided for pointers to functions.

Which operator is used to initialize value for default arguments?

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.

Does C default argument?

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.

Which case default argument passing in function is not allowed?

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.

What is a void pointer in C?

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.

What is a null pointer in C11?

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. ”

Is pointer null after returning from function call in C?

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++?

Why can’t we do arithmetic with void pointers?

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.


Video Answer


3 Answers

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);
  }
};
like image 179
康桓瑋 Avatar answered Oct 22 '22 08:10

康桓瑋


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.

like image 22
Aconcagua Avatar answered Oct 22 '22 09:10

Aconcagua


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.

like image 43
mch Avatar answered Oct 22 '22 07:10

mch