Arity of a generic lambda

前端 未结 5 1247
说谎
说谎 2020-12-01 23:53

It is possible to deduce arity of a non-generic lambda by accessing its operator().

template 
struct fInfo : fInfo

        
5条回答
  •  执笔经年
    2020-12-02 00:38

    This is a c++17 solution that works with generic and variadic lambdas and functors with variadic templatet operator(). the idea is to recursively simulate the call with descending number of arguments and use SFINAE to break recursion when the first matching number of arguments is found. It compilers on gcc >= 7 and Clang >=5. A working example can be found here.

    #include
    
    constexpr size_t max_arity = 10;
    
    struct variadic_t
    {
    };
    
    namespace detail
    {
        // it is templated, to be able to create a
        // "sequence" of arbitrary_t's of given size and
        // hece, to 'simulate' an arbitrary function signature.
        template 
        struct arbitrary_t
        {
            // this type casts implicitly to anything,
            // thus, it can represent an arbitrary type.
            template 
            operator T &&();
    
            template 
            operator T &();
        };
    
        template ()(arbitrary_t{}...))>
        constexpr auto test_signature(std::index_sequence)
        {
            return std::integral_constant{};
        }
    
        template 
        constexpr auto arity_impl(int) -> decltype(test_signature(std::make_index_sequence{}))
        {
            return {};
        }
    
        template  0)>>
        constexpr auto arity_impl(...)
        {
            // try the int overload which will only work,
            // if F takes I-1 arguments. Otherwise this
            // overload will be selected and we'll try it 
            // with one element less.
            return arity_impl(0);
        }
    
        template 
        constexpr auto arity_impl()
        {
            // start checking function signatures with max_arity + 1 elements
            constexpr auto tmp = arity_impl(0);
            if constexpr (tmp == MaxArity + 1)
            {
                // if that works, F is considered variadic
                return variadic_t{};
            }
            else
            {
                // if not, tmp will be the correct arity of F
                return tmp;
            }
        }
    }
    
    template 
    constexpr auto arity(F&& f) { return detail::arity_impl, MaxArity>(); }
    
    template 
    constexpr auto arity_v = detail::arity_impl, MaxArity>();
    
    template 
    constexpr bool is_variadic_v = std::is_same_v)>, variadic_t>;
    

    Usage:

    auto l = [](auto...){};
    static_assert(is_variadic_v);
    

    and:

    auto l = [](auto, auto, auto){};
    static_assert(!is_variadic_v);
    static_assert(arity(l) == 3);
    

提交回复
热议问题