Is it possible to use 'enable_if' and 'is_same' with variadic function templates?

后端 未结 3 363
一向
一向 2020-12-10 06:09

These two non-variadic function templates do compile:

template 
typename std::enable_if::value, v         


        
相关标签:
3条回答
  • 2020-12-10 06:32

    If you are bound to C++ 11 and want to keep your code readable, you can implement simple equivalent of is_same which matches multiple types:

    template <typename Ref, typename T1, typename... TN>
    struct all_match;
    
    template <typename Ref, typename T>
    struct all_match<Ref,T>
    {
        static constexpr bool value = std::is_same<T,Ref>::value;
    };
    
    template <typename Ref, typename T1, typename... TN>
    struct all_match
    {
        static constexpr bool value = std::is_same<T1,Ref>::value && all_match<Ref, TN...>::value;
    };
    

    And then (note, that the reference type goes first):

    template <typename T, typename... U>
    typename std::enable_if<all_match<int, U...>::value, void>::
    type testFunction(T a, U... bs) {
        std::cout << "bs are integers\n";
    }
    

    Live demo: click.

    C++ 17 introduces fold expression which allows you to fold parameter pack (...) over a binary operator. You can use it to easy apply std::is_same<> for all types in a parameter pack and then and the values:

    template <typename T, typename... U>
    typename std::enable_if<(std::is_same<U, float>::value && ...), void>::
    type testFunction(T a, U... bs) {
        std::cout << "bs are floats\n";
    }
    
    template <typename T, typename... U>
    typename std::enable_if<(std::is_same<U, int>::value && ...), void>::
    type testFunction(T a, U... bs) {
        std::cout << "bs are ints\n";
    }
    

    You can check demo for this version here.

    0 讨论(0)
  • 2020-12-10 06:36

    Or you could simply make use of additional variadic pack to test if all template arguments are the same and equal to a given type (C++11):

    #include <type_traits>
    #include <iostream>
    
    template <class...>
    struct pack { };
    
    template <typename T, typename... U>
    typename std::enable_if<std::is_same<pack<int, U...>, pack<U..., int>>::value, void>::
    type testFunction(T a, U... bs) {
        std::cout << "bs are integers\n";
    }
    
    template <typename T, typename... U>
    typename std::enable_if<std::is_same<pack<float, U...>, pack<U..., float>>::value, void>::
    type testFunction(T a, U... bs) {
        std::cout << "bs are floats\n";
    }
    
    int main() {
        testFunction(1, 2, 3, 4, 5);
        testFunction(1, 2.0f, 3.5f, 4.4f, 5.3f);
    }
    

    [live demo]

    Output:

    bs are integers
    bs are floats
    
    0 讨论(0)
  • 2020-12-10 06:45

    Yes. You can use a fold expression in C++17:

    template <typename T, typename... U>
    typename std::enable_if<(std::is_same<U, float>::value && ...), void>::
    type testFunction(T a, U... bs) {
        std::cout << "bs are floats\n";
    }
    

    In C++11, you can reimplement std::conjunction:

    template<class...> struct conjunction : std::true_type { };
    template<class B1> struct conjunction<B1> : B1 { };
    template<class B1, class... Bn>
    struct conjunction<B1, Bn...> 
        : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
    

    template <typename T, typename... U>
    typename std::enable_if<
        std::conjunction_v<std::is_same<U, float>...>, 
        void
    >::type testFunction(T a, U... bs) {
        std::cout << "bs are floats\n";
    }
    
    0 讨论(0)
提交回复
热议问题