How do I determine if a type is callable with only const references?

后端 未结 6 1822
清酒与你
清酒与你 2021-02-04 13:08

I want to write a C++ metafunction is_callable that defines value to be true, if and only if the type F has the function cal

6条回答
  •  终归单人心
    2021-02-04 13:44

    After hours of playing around and some serious discussions in the C++ chat room, we finally got a version that works for functors with possibly overloaded or inherited operator() and for function pointers, based on @KerrekSB's and @BenVoigt's versions.

    #include 
    #include 
    
    template 
    class Callable{
      static int tester[1];
      typedef char yes;
      typedef yes (&no)[2];
    
      template 
      static typename std::enable_if::value, char>::type
          sfinae(decltype(std::declval()(std::declval()...)) (C::*pfn)(Brgs...));
    
      template 
      static typename std::enable_if::value, char>::type
          sfinae(decltype(std::declval()(std::declval()...)) (C::*pfn)(Brgs...) const);
    
      template 
      static char sfinae(decltype(std::declval()(std::declval()...)) (G::*pfn)(Brgs...));
    
      template 
      static char sfinae(decltype(std::declval()(std::declval()...)) (G::*pfn)(Brgs...) const);
    
      template 
      static yes test(int (&a)[sizeof(sfinae(&G::operator()))]);
    
      template 
      static no test(...);
    
    public:
      static bool const value = sizeof(test(tester)) == sizeof(yes);
    };
    
    template
    struct Helper{ R operator()(Args...); };
     
    template
    class Callable
      : public Callable, Args...>{};
    

    Live example on Ideone. Note that the two failing tests are overloaded operator() tests. This is a GCC bug with variadic templates, already fixed in GCC 4.7. Clang 3.1 also reports all tests as passed.

    If you want operator() with default arguments to fail, there is a possible way to do that, however some other tests will start failing at that point and I found it as too much hassle to try and correct that.

    Edit: As @Johannes correctly notes in the comment, we got a little inconsistency in here, namely that functors which define a conversion to function pointer will not be detected as "callable". This is, imho, pretty non-trivial to fix, as such I won't bother with it (for now). If you absolutely need this trait, well, leave a comment and I'll see what I can do.


    Now that all this has been said, IMHO, the idea for this trait is stupid. Why whould you have such exact requirements? Why would the standard is_callable not suffice?

    (Yes, I think the idea is stupid. Yes, I still went and built this. Yes, it was fun, very much so. No, I'm not insane. Atleast that's what I believe...)

提交回复
热议问题