How to check if template argument is a callable with a given signature

后端 未结 5 1902
没有蜡笔的小新
没有蜡笔的小新 2020-12-14 16:58

Basically, what I want to achieve is compile-time verification (with possibly nice error message) that registered callable (either a function, a lambda, a struct with call o

5条回答
  •  刺人心
    刺人心 (楼主)
    2020-12-14 17:34

    In C++17 there is trait is_invocable, which does exactly what you ask for. Its advantage over is_convertible,...> is that you don't have to specify return type. It might sound like overkill but recently I had problem that had to use it, exactly my wrapper function deduced its return type from passed Callable, but I've passed templated lambda like this one [](auto& x){return 2*x;}, so return type of it was deduced in subcall. I couldn't convert it into std::function and I ended up using local implementation of is_invocable for C++14. I cannot find the link where I got it from though... Anyway, the code:

    template 
    struct is_invocable
    {
        template 
        static auto test(U* p) -> decltype((*p)(std::declval()...), void(), std::true_type());
        template 
        static auto test(...) -> decltype(std::false_type());
    
        static constexpr bool value = decltype(test(0))::value;
    };
    

    and for your example:

    struct A {
    using Signature = void(int, double);
    
    template 
    void Register(Callable &&callable) {
        static_assert(is_invocable::value, "not foo(int,double)");
        callback = callable;
    }
    
    std::function callback;
    };
    

提交回复
热议问题