Checking type of parameter pack using enable_if

前端 未结 5 2095
野的像风
野的像风 2021-02-19 21:38

Since there is a restriction on allowed non-type variadic templates, I am trying to write a function taking an arbitrary number of doubles using enable_if. In essen

相关标签:
5条回答
  • 2021-02-19 22:05

    I think the simpler would be to use std::initializer_list:

    foo(std::initializer_list<double> args)
    {
        // Your stuff.
    }
    

    instead of variadic template. It may require to use {} instead of/ in addition to ()

    0 讨论(0)
  • 2021-02-19 22:10

    Here is another (c++11) version (heavily inspired by the T.C.'s one above):

    #include <type_traits>
    
    template <typename To, typename From, typename... R>
    struct are_all_convertible {
        constexpr static bool value = std::is_convertible<From,To>::value &&
                                      are_all_convertible<To,R...>::value;
    };
    
    template <typename To, typename From>
    struct are_all_convertible<To,From> {
        constexpr static bool value = std::is_convertible<From,To>::value;
    };
    
    template<typename... T,
    typename = typename std::enable_if<are_all_convertible<double, T...>::value>::type>
    foo(T... t){ /* code here */}
    
    0 讨论(0)
  • 2021-02-19 22:14

    The bool_pack trick again.

    template<bool...> struct bool_pack;
    template<bool... bs> 
    using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;
    

    Then

    template<class R, class... Ts>
    using are_all_convertible = all_true<std::is_convertible<Ts, R>::value...>;
    

    and finally

    template<typename... T,
    typename = typename enable_if<are_all_convertible<double, T...>::value>::type>
    foo(T... t){ /* code here */}
    
    0 讨论(0)
  • 2021-02-19 22:15

    Here is a generic approach – a TMP for binary folding, using C++14. First, let's define the basic combining operations:

    #include <type_traits>
    
    struct and_op
    {
        using type = bool;
        using identity = std::true_type;
        template <bool A, bool B> static constexpr bool value = A && B;
    };
    
    struct or_op
    {
        using type = bool;
        using identity = std::false_type;
        template <bool A, bool B> static constexpr bool value = A || B;
    };
    

    Now the actual fold mechanic:

    template <typename Op, typename Op::type...>
    struct fold;
    
    template <typename Op>
    struct fold<Op> : Op::identity {};
    
    template <typename Op, typename Op::type Val>
    struct fold<Op, Val>
        : std::integral_constant<typename Op::type
        , Val> {};
    
    template <typename Op, typename Op::type Val, typename Op::type... Tail>
    struct fold<Op, Val, Tail...>
        : std::integral_constant<typename Op::type
        , Op::template value<Val, fold<Op, Tail...>::value>> {};
    

    Next, we need a way to create unary traits from binary traits by binding:

    template <template <typename, typename> class BPred, typename T>
    struct bind_pred
    {
        template <typename U>
        struct pred_1st : std::integral_constant<bool, BPred<T, U>::value> {};
        template <typename U>
        struct pred_2nd : std::integral_constant<bool, BPred<U, T>::value> {};
    };
    

    Finally, a helper wrapper to combine the result of applying a unary predicate:

    template <typename Op, template <typename> class UPred, typename ...Args>
    struct fold_pred : fold<Op, UPred<Args>::value...> {};
    

    That's it. Now let's get to work:

    template <typename T>
    using maybe_double = bind_pred<std::is_convertible, double>::pred_2nd<T>;
    
    #include <iomanip>
    #include <iostream>
    
    int main()
    {
        std::cout
            << std::boolalpha
            << fold_pred<and_op, maybe_double, int, float>::value << '\n'
            << fold_pred<and_op, maybe_double, int, float, void>::value << '\n';
    }
    

    In C++17 (or C++1z, rather), you can write direct solutions with less code thanks to the new fold expressions. For example:

    template <template <typename> class UPred, typename ...Args>
    static constexpr bool pred_all = (UPred<Args>::value && ...);
    //                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unary fold
    

    Usage:

    static_assert(pred_all<maybe_double, int, float>);
    
    0 讨论(0)
  • 2021-02-19 22:18

    You could use fold expression in c++17 to do the same thing as other answers posted here but without the hassle of creating templates.

    #include <type_traits>
    
    template <typename... T, typename = 
        typename std::enable_if<
            (true && ... && std::is_convertible_v<T, ___YOUR_TYPE___>),
            void
        >::type
    >
    constexpr auto foo(T...) noexcept {
            // your code 
    }
    
    0 讨论(0)
提交回复
热议问题