[cfe-dev] problem with std::function and virtual destructor
Howard Hinnant
hhinnant at apple.com
Sun Jul 15 16:40:06 PDT 2012
On Jul 15, 2012, at 3:50 PM, Howard Hinnant <hhinnant at apple.com> wrote:
> On Jul 15, 2012, at 3:59 AM, Richard Smith <richard at metafoo.co.uk> wrote:
>
>> I'm not sure why instantiating std::function<void(X&)>::operator= would require X to be complete -- libstdc++ does not behave that way. It's possible this is a bug in libc++, but it's also possible that the standard allows this behavior and libstdc++ is just more permissive. Hopefully Howard can help with that part.
>
> Just fyi, I'm not ignoring this question. I just haven't figured out yet why I'm requiring complete types. Working...
This is arguably a bug in libc++, but I need some more time before I'm ready to fix it.
libc++ has a conforming extension for std::function to check and see if the F in:
template<class F> function& operator=(F&&);
is callable. The standard requires that F be callable for argument types ArgTypes and return type R, but the onus is on the client to meet that requirement. Failure to do so results in undefined behavior. libc++'s extension is to enforce that requirement and thus emit a diagnostic if the client fails to meet it:
template<class _Fp>
typename enable_if
<
__callable<typename decay<_Fp>::type>::value,
function&
>::type
operator=(_Fp&&);
__callable builds on __invokable and __invoke_of, which are implementation details originally invented for other parts of libc++, and only applied to std::function relatively recently.
When these traits were first invented, they were used in async and bind. In this bug:
http://llvm.org/bugs/show_bug.cgi?id=9975
Richard helped me diagnose this invalid program:
#include <functional>
//#include <string>
using namespace std::placeholders;
template <typename Functor>
static void doIt(Functor f)
{
f("");
}
void method(const std::string&) {}
int main()
{
doIt(std::bind(&method, _1));
}
(I forgot to #include <string>). The error message was so terrible that it took Richard's expertise to debug this. At that time I decided to add "complete type" checks to __invokable, which greatly increased the quality of the error message of the above ill-formed program. Now even a mortal such as myself could debug it.
Subsequently, and much later, the std::function's __callable inherited those complete type checks.
If we really need to relax the complete-type-check for function, I could split the __invokable trait: have one with complete type checks for bind, and one without for function. But for tonight, this explanation of what has happened is as far as I'm getting.
Comments/suggestions most welcome.
Howard
More information about the cfe-dev
mailing list