Strange behavior with std::function

…衆ロ難τιáo~ 提交于 2019-12-05 15:12:38

Looks like a bug to me. First, here's a simplified example that doesn't play any games with casts:

#include <functional>
#include <iostream>

typedef void (*VF)();

VF Test() {
    return nullptr;
}

int main(int argc, char* argv[]) {
    std::function<void()> foo(Test());
    std::cout << !!foo << std::endl;
    return 0;
}

It still prints 1 with GCC. It shouldn't:

20.8.11.2.1
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
7 Requires: F shall be CopyConstructible. f shall be Callable (20.8.11.2) for argument types ArgTypes and return type R. The copy constructor and destructor of A shall not throw exceptions.
8 Postconditions: !*this if any of the following hold:

  • f is a NULL function pointer.
  • f is a NULL pointer to member.
  • F is an instance of the function class template, and !f

I don't think the code is doing what you think it does. This line:

foo = reinterpret_cast<void(*)()>(Test());

means that you receive a void* from Test(). You then procede to reinterpret_cast this pointer-to-object into a pointer-to-function. This is not allowed and therefore the code yields undefined behavior and therefore any output of the compiler is valid.

The relevant parts of the standard are

5.2.10 Reinterpret cast [expr.reinterpret.cast]

8 Converting a function pointer to an object pointer type or vice versa is conditionally-supported. The meaning of such a conversion is implementation-defined, except that if an implementation supports conversions in both directions, converting a prvalue of one type to the other type and back, possibly with dierent cv- qualification, shall yield the original pointer value.

9 The null pointer value (4.10) is converted to the null pointer value of the destination type. [Note: A null pointer constant of type std::nullptr_t cannot be converted to a pointer type, and a null pointer constant of integral type is not necessarily converted to a null pointer value. — end note ]

and

4.10 Pointer conversions [conv.ptr]

1 A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type.

(emphasis mine)

Here's a reduced test case taking std::function (and its possible bugs) out of the equation:

#include <iostream>

int main() {
    using fp_t = void(*)();
    void* vn = nullptr;
    fp_t foo = reinterpret_cast<fp_t>(vn); // GCC: warning, Clang: silence
    //fp_t foo = reinterpret_cast<fp_t>(nullptr); // error (GCC and Clang!)
    std::cout << !!foo << std::endl;
}

Live example

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!