Search code examples
c++variadic-templatesenable-if

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


These two non-variadic function templates do compile:

template <typename T, typename U>
typename std::enable_if<std::is_same<U, int>::value, void>::
type testFunction(T a, U b) {
    std::cout << "b is integer\n";
}

template <typename T, typename U>
typename std::enable_if<std::is_same<U, float>::value, void>::
type testFunction(T a, U b) {
    std::cout << "b is float\n";
}

however, similar variadic templates do not compile:

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 integers\n";
}

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";
}

Maybe I am trying to do something that cannot be done. I know that similar functionality can be achieved using initializer lists, but I would like to avoid curly brackets required for initializer list arguments.


Solution

  • 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";
    }