我正在寻找一种非递归的现代方法(至少可以使用 gcc 和 clang 进行编译)来查找可变参数包的 𝑛th 元素。事实上,似乎存在这样一个使用 c++20 概念的解决方案:Kris Jusiak 在 CppCon、CppNow 和 Meeting Cpp 上发表了演讲nth pack element,所有这些都在 2022 年进行,并且都可以在 YouTube 上找到; Alex Dathskovsky 写了一篇 LinkedIN 文章 Nth element variadic pack extract (https://www.linkedin.com/pulse/nth-element-variadic-pack-extraction-alex-dathskovsky-);当然还有其他地方可以找到这种情况。这两种解决方案非常相似,据称都表现得很好;我将在下面包括前者。遗憾的是,上述示例都无法编译。这是 Jusiak 演讲中给出的编译器资源管理器链接 (https://godbolt.org/z/WPhe5MerW),下面是副本:
#include <cstddef> // adding #include <concepts> changes nothing
#include <utility>
template <typename, std::size_t> concept prefix = true;
template <auto N>
constexpr auto nth_element(auto... args) {
return [&]<auto... Is>(std::index_sequence<Is...>) {
return [] (prefix<Is> auto..., auto arg, auto...) {
return arg;
}(args...);
}(std::make_index_sequence<N>());
}
static_assert(1 == nth_element<0>(1));
static_assert(1 == nth_element<0>(1, 2));
static_assert(2 == nth_element<1>(1, 2)); // this line throws an error
static_assert(1 == nth_element<0>(1, 2, 3));
static_assert(2 == nth_element<1>(1, 2, 3)); // and this one
static_assert(3 == nth_element<2>(1, 2, 3)); // and this one
这不能在本地编译,也不能在 godbolt 上编译。评论是我自己的。以下是
gcc
的抱怨归结为:
<source>:10:27: error: mismatched argument pack lengths while expanding 'prefix<auto:2, Is>'
9 | return [] (prefix<Is> auto..., auto arg, auto...) {
和
clang
s:
<source>:9:31: note: because substituted constraint expression is ill-formed: pack expansion
contains parameter packs 'auto:1' and 'Is' that have different lengths (0 vs. 1)
9 | return [] (prefix<Is> auto..., auto arg, auto...) {
这似乎会导致“约束不满足”,因此模板参数推导/替换失败,导致第 9 行中的嵌套 lambda 没有匹配(函数)调用。
我尝试四处寻找,但无济于事。不确定是因为
免责声明我不是专业人士,还是真的有点棘手!我不知道该怎么办。我尝试过一些愚蠢的事情,比如到处添加和删除省略号,比如前缀概念中的 std::size_t...
,或者我们有问题的 lambda 中的
prefix<Is...>
,但都没有帮助。 LinkedIN 的帖子和会议演讲也试图对其进行分解,我希望能够充分消化这些内容,以便能够找到解决方案 - 但事实并非如此。我真诚地为没有提供更好的尝试而道歉。是的,存在其他可行的解决方案,并且可以在上述来源中找到一些解决方案,但我特别有兴趣获得其中一个使用概念进行编译的解决方案。我还发现了一些可能有用且相关的 SO 帖子,但我无法弄清楚如何使用它们来提供帮助。许多提供递归作为解决方案。
扩展 std::index_sequence 和可变参数包时参数包长度不匹配(请参阅 questions/74805917/mismatched-argument-pack-lengths-while-expanding-stdindex-sequence-and-variadi)
现在,也许这篇文章已经太长了,下面的内容可能更适合作为(单独的)后续问题,但在 Andrei Alexandrescu 的 CppCon 2021 演讲中
(位于YouTube)他建议将以下内容添加到标准中以帮助处理参数包:
template<typename... Ts> struct type_sequence {};
//
template<typename... Ts> struct head;
template<typename T, typename... Ts>
struct head<type_sequence<T, Ts...>>
{
using type = T;
};
template<typename T>
using head_t = typename head<T>::type;
//
template<typename... Ts> struct tail;
template<typename T, typename... Ts>
struct tail<type_sequence<T, Ts...>>
{
using type = type_sequence<Ts...>;
};
template<typename T>
using tail_t = typename tail<T>::type;
//
template<typename T, typename List> struct cons;
template<typename T, typename... Ts>
struct cons<T, type_sequence<Ts...>>
{
using type = type_sequence<T, Ts...>;
};
template<typename T, typename List>
using cons_t = typename cons<T, List>::type;
我想知道在寻找包中第 𝑛th
元素的概念扩展解决方案中,我们是否能够找到一种方法来用这个 std::index_sequence
替换
type_sequence
。预先感谢您!#include <array>
#include <tuple>
template <std::size_t N, typename... args_t>
constexpr auto nth_element(args_t... args)
{
return std::get<N>(std::forward_as_tuple(args...));
}
int main()
{
static_assert(1 == nth_element<0>(1));
static_assert(1 == nth_element<0>(1, 2));
static_assert(2 == nth_element<1>(1, 2)); // this line throws an error
static_assert(1 == nth_element<0>(1, "Hello", 3.0));
static_assert(2 == nth_element<1>(1, 2, 3)); // and this one
static_assert(3 == nth_element<2>(1, 2, 3)); // and this one
}