c++c++17variadic-templatesvariadic-tuple-types

count std::optional types in variadic template tuple


I've got a parameter pack saved as a tuple in some function traits struct. How can I find out, how many of those parameters are std::optional types?

I tried to write a function to check each argument with a fold expression, but this doesn't work as I only pass a single template type which is the tuple itself.

void foo1(){}
void foo2(int,float){}
void foo3(int, std::optional<int>, float, std::optional<int>){}
void foo4(int, std::optional<int>, bool){}

template<typename R, typename... TArgs>
struct ftraits<R(TArgs...)>
{
    using ret = R;
    using args = std::tuple<TArgs...>;
};

template<typename T>
struct is_optional : std::false_type
{
};

template<typename T>
struct is_optional<std::optional<T>> : std::true_type
{
};

template<typename... Ts>
constexpr auto optional_count() -> std::size_t
{
    // doesn't work since Ts is a single parameter with std::tuple<...>
    return (0 + ... + (is_optional<Ts>::value ? 1 : 0));
}

int main() {
    using t1 = typename ftraits<decltype(foo1)>::args;
    std::cout << optional_count<t1>() << std::endl; // should print 0
    using t2 = typename ftraits<decltype(foo2)>::args;
    std::cout << optional_count<t2>() << std::endl; // should print 0
    using t3 = typename ftraits<decltype(foo3)>::args;
    std::cout << optional_count<t3>() << std::endl; // should print 2
    using t4 = typename ftraits<decltype(foo4)>::args;
    std::cout << optional_count<t4>() << std::endl; // should print 1
}

Solution

  • You can use template partial specialization to get element types of the tuple and reuse the fold-expression

    template<typename>
    struct optional_count_impl;
    
    template<typename... Ts>
    struct optional_count_impl<std::tuple<Ts...>> { 
      constexpr static std::size_t count = 
        (0 + ... + (is_optional<Ts>::value ? 1 : 0));
    };
    
    template<typename Tuple>
    constexpr auto optional_count() -> std::size_t {      
      return optional_count_impl<Tuple>::count;
    }
    

    Demo