如何检测std::integer_sequence中特定数字的索引?

How to detect index of a specific number in a std::integer_sequence?

我基本上使用这个问题作为参考起草了编译时素数检查: Compile time prime checking

我有可用的 IsPrime<3>::value。

我想设计一个查找元函数,它基本上可以在编译时识别我的整数序列中是否有素数,如果有则 returns 索引 else returns -1;

例子

我无法全神贯注于参数包,任何好的例子或适当的解释解决方案都会有很大帮助。

大声思考如下内容,但无法全神贯注,如何获取索引以及如何在找到序列中的第一个素数后停止迭代

template<typename T... args>
struct find_prime{
   static constexpr int value = is_prime<args>::value ? increement++ : is_prime<...>::args; 
};

抱歉,如果这听起来像一个愚蠢的方法,无法弄清楚如何使用索引进行迭代

这里是一个 example,代码少得多:

template <int ...Ints>
constexpr int find_prime() {
    constexpr auto res = fp<Ints...>(std::make_index_sequence<sizeof...(Ints)>{}); 
    return (res == sizeof...(Ints)) ? -1 : res;
}

template <int ...Ints, auto ...Indices>
constexpr int fp(std::index_sequence<Indices...>) {
    return std::min({ (is_prime(Ints) ? Indices : sizeof...(Indices))... });
}

这个想法是将每个数字绑定到它在列表中的索引,并且只是 return 列表中作为质数的最小索引。如果索引列表中的所有条目都是列表本身的长度,则程序应 return -1.

这可以通过递归模板来完成。当找到质数时,递归提前终止。

// Base failure case: our list is empty (or the specialization below would match)
template <int, int...>
struct find_prime_impl {
    static constexpr int value = -1;
};

// Specialization for at least one item remaining.  If it's prime, the current
// index is assigned to value; otherwise we recurse with an incremented index,
// and without the first item.
template <int Index, int Head, int... Tail>
struct find_prime_impl<Index, Head, Tail...> {
    static constexpr int value = [] {
        if constexpr (is_prime<Head>::value) {
            return Index;
        } else {
            return find_prime_impl<Index + 1, Tail...>::value;
        }
    }();
};

// Calls the recursive template with the initial index 0.
template <int... Values>
struct find_prime : find_prime_impl<0, Values...> {};

immediately-invoked lambda 允许我们使用 if constexpr,这意味着编译器可以在满足终止情况时跳过实例化 find_prime_impl 的递归使用。三元运算符不会以这种方式“short-circuit”实例化,并且仍会实例化整个递归链一直到 find_prime_impl<Index>.

(Demo)


要直接使用 std::integer_sequence,调整实现以使其符合预期:

// Failure case when the type isn't std::integer_sequence
template <int, typename>
struct find_prime_impl {};

// Failure case when our list is empty (or the specialization below would match)
template <typename TInt, int Index>
struct find_prime_impl<Index, std::integer_sequence<TInt>> {
    static constexpr int value = -1;
};

// Specialization for at least one item remaining.  If it's prime, the current
// index is assigned to value; otherwise we recurse with an incremented index,
// and without the first item.
template <typename TInt, int Index, TInt Head, TInt... Tail>
struct find_prime_impl<Index, std::integer_sequence<TInt, Head, Tail...>> {
    static constexpr int value = [] {
        if constexpr (is_prime<Head>::value) {
            return Index;
        } else {
            return find_prime_impl<
                Index + 1,
                std::integer_sequence<TInt, Tail...>
            >::value;
        }
    }();
};

// Calls the recursive template with the initial index 0.
template <typename T>
struct find_prime : find_prime_impl<0, T> {};