Home > Software engineering >  How to prevent std::function to bool conversion in c function overloading?
How to prevent std::function to bool conversion in c function overloading?

Time:09-24

How to prevent std::function to bool conversion in C function overloading? such as

class Object final {
    
public:
    Object(bool boolean) : type_(22)  {}  //#1
    Object(const std::function<int(int*, int)>  value) : type_(11) {}  //#2
    
    int rettype() { return type_; };
    
private:
    int type_;
};


int Println(int *args, int nargs) {
  printf("Println\n");
  return 0;
}

int main() {
    cout << Object(Println).rettype() << endl; // 22
    cout << Object(std::function<int(int*, int)>(Println)).rettype() << endl; // 11
}

I want to call #2 through Object(Println) instead of Object(std::function<int(int*, int)>(Println)),but the result is that #1 is called

How should I achieve this?

CodePudding user response:

The modern C solution here would be Object::Object(std::invocable<int*, int> auto f)

You don't care exactly what the type of f is - that's clear from the fact that you consider std::function<int(int*, int)> and int(*)(int*, int)> interchangeable. std::invocable is slightly more general than that: it says anything callable is also OK. A lambda would also work.

CodePudding user response:

How about adding a function pointer constructor?

Object(int (*value)(int*, int)) : Object(std::function<int(int*, int)>(value)) {}

You can also alias the function type:

using FunctionType = int (*)(int*, int);
Object(FunctionType value) : Object(std::function<int(int*, int)>(value)) {}

CodePudding user response:

Why not a templated constructor which requires that the passed type is convertible to the desired function type?

    template<typename F,
             typename std::enable_if<std::is_convertible<F, std::function<int(int*, int)>>::value, bool>::type = true>
    Object(const F&) : type_(11) {}

(Works with -std=c 11.)

The advantage is that you don't even have to truly have any std::function object at run time. You simply check at compile time that it could be converted to it, but then you use the callable as it is, being it a function pointer, a lambda, or whatever.

CodePudding user response:

Check compiler warnings

warning: the address of 'int Println(int*, int)' will never be NULL [-Waddress]

It means that function pointer automatically auto converting the boolean integral type.

To prevent this you can handle function pointer type by additional type deduction specifier. std::function is a functional object e.g. functor, not a raw C function pointer and simply have a converting constructor

For example:

For example:

#include <iostream>
#include <functional>

class Object final {

public:
    explicit Object(bool boolean) : type_(22)  {}  //#1
    explicit Object(int(*)(int*,int)) : type_(11) {}
    explicit Object(const std::function<int(int*, int)>&  value) : type_(11) {}  //#2

    int rettype() { return type_; };

private:
    int type_;
};

int Println(int *args, int nargs)
{
  std::cout << "Println" << std::endl;
  return 0;
}

struct PrintLine
{
    int operator()(int*, int)
    {
        std::cout << "PrintLine" << std::endl;
        return 0;
    }
};

int main(int argc, const char** argv)
{
    std::cout << Object(Println).rettype() << std::endl; // 11
    PrintLine pl;
    std::cout << Object(pl).rettype() << std::endl; // 11
    std::cout << Object(1).rettype() << std::endl; // 22
    return 0;
}

CodePudding user response:

You can use only one constructor, but template and select what you want to do inside

template<class T>
Object(T t) {
    if( std::is_same_v<T,bool>::value )
    {
        type_ = 22;
    }
    else
    {
        type_ = 11;
    }
}

demo 17 : https://wandbox.org/permlink/0eMXkH1l8HzbdfC0
demo 11 : https://wandbox.org/permlink/rOP4JRAP2Ywb1osf
demo 11 in member initializer list : https://wandbox.org/permlink/6QDD4Vdo9TaqU4fT

It's only a POC, you may want check if the type is a type you want and fail if it's not what you expect.

  • Related