计数可变模板元组中的 std::optional 类型

count std::optional types in variadic template tuple

我在某些函数特征结构中将参数包保存为元组。 我怎样才能知道这些参数中有多少是 std::optional 类型?

我尝试编写一个函数来使用折叠表达式检查每个参数,但这不起作用,因为我只传递了一个模板类型,即元组本身。

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
}

您可以使用 std::tuple_size 获取元组的大小,然后使用递归模板迭代其所有成员。在该模板中,您可以假装使用 std::declval 构造元组实例,使用 std::get 获取当前索引处的值,最后使用 decltype 获取该值的类型.

示例实现:

#include <optional>
#include <tuple>
#include <utility>

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

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

template<typename Tuple, size_t i>
constexpr size_t optional_count_impl() {
    size_t val = is_optional<std::remove_reference_t<decltype(std::get<i>(std::declval<Tuple>()))>>::value ? 1 : 0;
    if constexpr (i) {
        val += optional_count_impl<Tuple, i - 1>();
    }
    return val;
}

template<typename Tuple>
constexpr size_t optional_count() {
    const size_t tuple_size = std::tuple_size<Tuple>::value;
    if constexpr (tuple_size == 0) {
        return 0;
    } else {
        return optional_count_impl<Tuple, tuple_size - 1>();
    }
}

using Tup1 = std::tuple<int, int, std::optional<size_t>, bool, std::optional<bool>, std::optional<std::optional<int>>>;

int main() {
    return optional_count<Tup1>();
}

您可以使用模板偏特化来获取 tuple 的元素类型并重用 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