[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