Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何从元组中删除第n个元素?_Algorithm_Templates_C++17_Variadic Templates_Template Meta Programming - Fatal编程技术网

Algorithm 如何从元组中删除第n个元素?

Algorithm 如何从元组中删除第n个元素?,algorithm,templates,c++17,variadic-templates,template-meta-programming,Algorithm,Templates,C++17,Variadic Templates,Template Meta Programming,我试图编写一个函数,从现有的std::tuple创建一个新的std::tuple,并跳过给定索引上的元素。例如: 我有一个元组t定义如下: constexpr auto t = std::tuple(1, 2, 3, 4); 我想把它复制到另一个元组。但是,我想跳过第n个元素。假设在本例中,我要跳过的第n个元素是3(这意味着我要跳过索引为2的元素)。这将产生一个新的元组,定义为: std::tuple(1, 2, 4); 这是迄今为止我得到的最接近的结果: template<std::

我试图编写一个函数,从现有的
std::tuple
创建一个新的
std::tuple,并跳过给定索引上的元素。例如:

我有一个元组
t
定义如下:

constexpr auto t = std::tuple(1, 2, 3, 4);
我想把它复制到另一个元组。但是,我想跳过第n个元素。假设在本例中,我要跳过的第n个元素是3(这意味着我要跳过索引为2的元素)。这将产生一个新的元组,定义为:

std::tuple(1, 2, 4);
这是迄今为止我得到的最接近的结果:

template<std::size_t N, typename T, std::size_t ... is>
constexpr auto fun(T&& tp, std::index_sequence<is...>&& i) noexcept {
    return std::tuple((is != N ? std::get<is>(tp) : 0) ...);
}

template<std::size_t N, std::size_t... elems>
constexpr auto fun2() noexcept {
    constexpr auto t = std::tuple(elems...);
    return fun<N>(std::forward_as_tuple(elems...), std::make_index_sequence<sizeof...(elems)>());
}
然而,这个问题是,三元运算符的两边都必须有匹配类型

我尝试的另一种方法是基于递归的:

template<std::size_t N, std::size_t head, std::size_t... tail>
constexpr auto fun3() noexcept {
    if constexpr(!sizeof...(tail))
        return std::tuple(head);

    if constexpr(sizeof...(tail) - 1 == N)
        return std::tuple_cat(fun3<N, tail...>());

    if constexpr(sizeof...(tail) - 1 != N)
        return std::tuple_cat(std::tuple(head), fun3<N, tail...>());
}
我错过了什么?如何复制元组并在复制过程中跳过其中一个元素

我使用的是C++17,我需要在编译时对函数进行求值。

怎么样

return std::tuple_cat( foo<is, N>::func(std::get<is>(tp)) ...);
(注意:未测试代码)


这几乎是您的三元运算符想法,但没有在两侧匹配类型的问题:只有正确的类型被实例化。

发布问题几分钟后,我找到了一个解决方法。这并不理想,但是嘿:

template<std::size_t N, typename T, std::size_t ... is>
constexpr auto fun(T&& tp, std::index_sequence<is...>&& i) noexcept {
    return std::tuple((is < N ? std::get<is>(tp) : std::get<is+1>(tp)) ...);
}

template<std::size_t N, std::size_t... elems>
constexpr auto fun2() noexcept {
    constexpr auto t = std::tuple(elems...);
    return fun<N>(std::forward_as_tuple(elems...), std::make_index_sequence<sizeof... (elems) - 1>());
}
模板
constexpr auto-fun(T&&tp,std::index_sequence&&i)无例外{
返回std::tuple((is
这样,我们复制第n个元素之前的所有元素,当我们到达第n个元素时,我们每增加一个索引1。我们不会超出范围,因为我们传递的索引_序列比传递的元组少1个元素


我希望这个答案能帮助一些人。

另一个解决方案是创建两个索引序列,引用元组的前后部分

template<std::size_t nth, std::size_t... Head, std::size_t... Tail, typename... Types>
constexpr auto remove_nth_element_impl(std::index_sequence<Head...>, std::index_sequence<Tail...>, std::tuple<Types...> const& tup) {
    return std::tuple{
        std::get<Head>(tup)...,
        // We +1 to refer one element after the one removed 
        std::get<Tail + nth + 1>(tup)...
    };
}

template<std::size_t nth, typename... Types>
constexpr auto remove_nth_element(std::tuple<Types...> const& tup) {
    return remove_nth_element_impl<nth>(
        std::make_index_sequence<nth>(), // We -1 to drop one element 
        std::make_index_sequence<sizeof...(Types) - nth - 1>(),
        tup
    );
}
模板
constexpr自动删除第n个元素\u impl(std::index\u序列,std::index\u序列,std::tuple const&tup){
返回std::tuple{
std::get(tup)。。。,
//我们+1表示删除后的一个元素
std::get(tup)。。。
};
}
模板
constexpr自动删除第n个元素(std::tuple const&tup){
返回删除元素\u impl(
std::make_index_sequence(),//We-1删除一个元素
std::make_index_sequence(),
塔普
);
}
下面是此函数的测试:

int main() {
    constexpr auto tup = std::tuple{1, 1.2, 'c'};
    constexpr auto tup2 = remove_nth_element<0>(tup);
    constexpr auto tup3 = remove_nth_element<2>(tup);
    static_assert(std::is_same_v<decltype(tup2), const std::tuple<double, char>>);
    static_assert(std::is_same_v<decltype(tup3), const std::tuple<int, double>>);
    return 0;
}
intmain(){
constexpr auto tup=std::tuple{1,1.2,'c'};
constexpr auto tup2=删除第n个元素(tup);
constexpr auto tup3=删除第n个元素(tup);
静态断言(std::is_same_v);
静态断言(std::is_same_v);
返回0;
}


此解决方案的优点是不构建中间元组,也不使用
std::tuple\u cat
,这两种方法都会对编译时间造成困难。

Uhmmm。。。之所以有效,是因为您有一个具有相同类型元素的
std::tuple
,因此
std::get(tp)
std::get(tp)
属于相同类型。对于泛型
std::tuple
而言,情况并非如此,对于
std::tuple\u cat()
解决方案:具有不同类型的三元运算符,您的三元运算符也会出现相同的错误。但是,也许可以从索引的角度应用此解决方案:
std::tuple(std::get(tp))是的,我需要它用于一个用例,在这个用例中,我在所有元素中都有相同的类型。但是您的解决方案要好得多,它可以与通用的
std::tuple
一起工作!只是一张纸条;在
std::get之后,您错过了另一个括号。您是否正确:括号错误。也许您可以删除:
std::tuple(std::get(tp)…)。无论如何:如果元组中的所有元素都是相同类型的,为什么不使用
std::array
?啊,我又错了,对不起!我用折叠表达式做了一些其他的事情,并开始认为我需要比我做的更多的括号。关于
std::array
,我想我可以用它们来实现我的目标。我真的不知道为什么我一开始没有做。这会让我的生活更轻松,哈哈。但这也不算太糟糕。如果我决定扩展该功能或将元组用于其他用途,那么即使没有其他用途,我也会有一个不错的基础。
template<std::size_t N, typename T, std::size_t ... is>
constexpr auto fun(T&& tp, std::index_sequence<is...>&& i) noexcept {
    return std::tuple((is < N ? std::get<is>(tp) : std::get<is+1>(tp)) ...);
}

template<std::size_t N, std::size_t... elems>
constexpr auto fun2() noexcept {
    constexpr auto t = std::tuple(elems...);
    return fun<N>(std::forward_as_tuple(elems...), std::make_index_sequence<sizeof... (elems) - 1>());
}
template<std::size_t nth, std::size_t... Head, std::size_t... Tail, typename... Types>
constexpr auto remove_nth_element_impl(std::index_sequence<Head...>, std::index_sequence<Tail...>, std::tuple<Types...> const& tup) {
    return std::tuple{
        std::get<Head>(tup)...,
        // We +1 to refer one element after the one removed 
        std::get<Tail + nth + 1>(tup)...
    };
}

template<std::size_t nth, typename... Types>
constexpr auto remove_nth_element(std::tuple<Types...> const& tup) {
    return remove_nth_element_impl<nth>(
        std::make_index_sequence<nth>(), // We -1 to drop one element 
        std::make_index_sequence<sizeof...(Types) - nth - 1>(),
        tup
    );
}
int main() {
    constexpr auto tup = std::tuple{1, 1.2, 'c'};
    constexpr auto tup2 = remove_nth_element<0>(tup);
    constexpr auto tup3 = remove_nth_element<2>(tup);
    static_assert(std::is_same_v<decltype(tup2), const std::tuple<double, char>>);
    static_assert(std::is_same_v<decltype(tup3), const std::tuple<int, double>>);
    return 0;
}