2
#include <iostream>
#include <functional>

typedef int(*SumFptr)(int,int);

int main()
{

    SumFptr ptr = nullptr;
    std::function<int(int)> func = std::bind(ptr, std::placeholders::_1, 42);
    std::cout << (func ? "true" : "false") << std::endl;

    return 0;
}

The output is true.

My expectation was false, like std::function{nullptr}. Is it a bug or correct behaviour and where can I read about it?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
stima
  • 131
  • 6

1 Answers1

1

How is the std::function supposed to know that the object it was constructed with contains a null pointer?

As far as it's concerned it has a callable object, it can't know that it is a callable object containing a null pointer (which would crash if called).

When you construct std::function{nullptr} it knows it doesn't have a callable object, and behaves exactly as if you'd called the default constructor. std::function{ anything_else } causes it to store anything_else and unless it is a null pointer (not an object that wraps a null pointer!) will consider itself to have a target object.

http://en.cppreference.com/w/cpp/utility/functional/function/operator_bool

std::function::operator bool
Return value: true if *this stores a callable function target, false otherwise.

Put another way, your program is almost exactly equivalent to this:

#include <iostream>
#include <functional>

using SumFPtr = int(*)(int,int);

struct BoundFunction {    
    SumFptr fptr;
    int y;

    int operator()(int x) const { return fptr(x, y); }
};

BoundFunction bind(SumFPtr fptr, int y)
{
    return BoundFunction{fptr, y};
}

int main()
{
    std::function<int(int)> func = bind(nullptr, 42);
    std::cout << (func ? "true" : "false") << std::endl;
}

Now it should be obvious that of course it prints "true", because the std::function contains a callable object.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • Yes, but isn't it easy to check arguments for bind? Like: bind(func, ...) { if (!func) save_nullptr_callable() } – stima Oct 01 '15 at 11:13
  • 1
    It would be theoretically possible, but `std::function` would have to know how to check for that. Do you see anything like that specified in the standard? Why should `bind` be a special case, when the same wouldn't work for my `BoundFunction` or for a lambda that captures a null function pointer? – Jonathan Wakely Oct 01 '15 at 11:36
  • 1
    Also, you could have some `func` that is a valid callable object but `!func` is true, so you'd need to be more careful to correctly identify a null pointer. – Jonathan Wakely Oct 01 '15 at 11:38