Search code examples
c++11c++14variadic-functionstemplate-meta-programming

Is it possible to check if some type doesn't exist in a parameter pack


I'm working on a C++14 project and I just wrote a function with parameter pack.

template <typename... Args>
void func(Args&&... args) {
    ...
}

The args should contain only int or std::string, it can't be any other types.

Is there any way to do the check at compile time? Maybe something as below?

template <typename... Args, std::enable_if_t<???* = nullptr>
void func(Args&&... args) {
    ...
}

Solution

  • This gets better with folds in C++17 and concepts in C++20, but you can test each element against int and std::string.

    The first end of the recursion is the primary template. If no specialisation matches, we are false.

    template <typename... Ts>
    struct all_int_or_string : std::false_type {};
    

    The other end of recursion is the empty pack, which is true.

    template <>
    all_int_or_string<> : std::true_type {};
    

    If we find int or std::string as the first element, recurse the remaining elements

    template <typename... Ts>
    struct all_int_or_string<int, Ts...> : all_int_or_string<Ts...> {}
    
    template <typename... Ts>
    struct all_int_or_string<std::string, Ts...> : all_int_or_string<Ts...> {}
    

    You probably also want to strip off qualifiers.

    template <typename T, typename... Ts>
    struct all_int_or_string<const T, Ts...> : all_int_or_string<T, Ts...> {}
    
    template <typename T, typename... Ts>
    struct all_int_or_string<volatile T, Ts...> : all_int_or_string<T, Ts...> {}
    
    template <typename T, typename... Ts>
    struct all_int_or_string<T &, Ts...> : all_int_or_string<T, Ts...> {}
    
    template <typename T, typename... Ts>
    struct all_int_or_string<T &&, Ts...> : all_int_or_string<T, Ts...> {}
    

    Used thusly

    template <typename... Args, std::enable_if_t<all_int_or_string<Args...>::value>* = nullptr>
    void func(Args&&... args) {
    }