You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用constexpr Lambda过滤std::tuple时编译失败的问题求助

constexpr Lambda过滤std::tuple时编译失败的问题求助

我想实现一个constexpr函数filter_tuple,功能是接收一个tuple和一个constexpr lambda,遍历tuple的每个元素,将lambda返回true的元素筛选出来,放到新的tuple中返回。这个函数必须是constexpr,且调用签名要符合需求。

以下是我目前写的代码:

#include <iostream>
#include <string>
#include <tuple>
#include <utility>
#include <type_traits>

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

template <typename... Args>
struct is_tuple<std::tuple<Args...>> : std::true_type {};

template <typename T>
static constexpr bool is_tuple_v = is_tuple<T>::value;

template <typename T, typename Fn>
constexpr auto check(const T& val, Fn&& fn) -> typename std::conditional<fn(val), std::tuple<>, std::tuple<T>>::type {
    if constexpr(fn(val)) {
        return std::make_tuple(val);
    } else {
        return std::make_tuple();
    }
}

template <typename T, typename Fn> requires (is_tuple_v<T>)
constexpr auto filter_tuple(const T& tpl, Fn&& filter_fn) {
    return [&]<std::size_t... Is>(std::index_sequence<Is...>){
        std::tuple_cat(check(std::get<Is>(tpl), filter_fn)...);
    }(std::make_index_sequence<std::tuple_size_v<T>>{});
}

template <class Tuple, typename F>
inline constexpr decltype(auto) for_each_in_tuple(Tuple&& tuple, F&& f) {
    return [] <std::size_t... I>
    (Tuple&& tuple, F&& f, std::index_sequence<I...>)
    {
        (f(std::get<I>(tuple)), ...);
        return f;
    }(std::forward<Tuple>(tuple), std::forward<F>(f),
      std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
}

auto tpl = std::make_tuple(
    [](auto a, auto b) { return a + b; },
    10,
    25,
    42.42,
    "Hello",
    std::string("there")
);

auto tpl_type_filtered = filter_tuple(tpl, []<typename T>(const T&) constexpr -> bool { return std::is_integral_v<T>; } );

int main() {
    // "tpl_type_filtered" = 10 25
    for_each_in_tuple(tpl_type_filtered, [](auto& val){ std::cout << val << std::endl; });
}

但是代码编译失败了,错误信息如下:

<source>:18:109: error: template argument 1 is invalid
18 | constexpr auto check(const T& val, Fn&& fn) -> typename std::conditional<fn(val), std::tuple<>, std::tuple<T>>::type {
|                                                                                                             ^~
<source>:18:109: error: template argument 1 is invalid
<source>:18:62: error: invalid use of template-name 'std::conditional' without an argument list
18 | constexpr auto check(const T& val, Fn&& fn) -> typename std::conditional<fn(val), std::tuple<>, std::tuple<T>>::type {
|                                                              ^~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/bits/move.h:57,
from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/bits/exception_ptr.h:41,
from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/exception:164,
from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/ios:41,
from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/ostream:40,
from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/iostream:41,
from <source>:1:
/opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/type_traits:2235:12: note: 'template<bool _Cond, class _Iftrue, class _Iffalse> struct std::conditional' declared here
2235 |     struct conditional
|            ^~~~~~~~~~~
<source>:18:73: error: expected initializer before '<' token
18 | constexpr auto check(const T& val, Fn&& fn) -> typename std::conditional<fn(val), std::tuple<>, std::tuple<T>>::type {
|                                                                         ^
<source>: In instantiation of 'filter_tuple<std::tuple<<lambda(auto:16, auto:17)>, int, int, double, const char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <lambda(const T&)> >(const std::tuple<<lambda(auto:16, auto:17)>, int, int, double, const char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, <lambda(const T&)>&&)::<lambda(std::index_sequence<Is ...>)> [with long unsigned int ...Is = {0, 1, 2, 3, 4, 5}; std::index_sequence<Is ...> = std::integer_sequence<long unsigned int, 0, 1, 2, 3, 4, 5>]':
<source>:30:6:   required from 'constexpr auto filter_tuple(const T&, Fn&&) [with T = std::tuple<<lambda(auto:16, auto:17)>, int, int, double, const char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >; Fn = <lambda(const T&)>]'
<source>:54:38:   required from here
<source>:29:29: error: 'check' was not declared in this scope
29 |         std::tuple_cat(check(std::get<Is>(tpl), filter_fn)...);
|                        ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:54:6: error: deduced type 'void' for 'tpl_type_filtered' is incomplete
54 | auto tpl_type_filtered = filter_tuple(tpl, []<typename T>(const T&) constexpr -> bool { return std::is_integral_v<T>; } );
|      ^~~~~~~~~~~~~~~~~
ASM generation compiler returned: 1
<source>:18:109: error: template argument 1 is invalid
18 | constexpr auto check(const T& val, Fn&& fn) -> typename std::conditional<fn(val), std::tuple<>, std::tuple<T>>::type {
|                                                                                                             ^~
<source>:18:109: error: template argument 1 is invalid
<source>:18:62: error: invalid use of template-name 'std::conditional' without an argument list
18 | constexpr auto check(const T& val, Fn&& fn) -> typename std::conditional<fn(val), std::tuple<>, std::tuple<T>>::type {
|                                                              ^~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/bits/move.h:57,
from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/bits/exception_ptr.h:41,
from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/exception:164,
from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/ios:41,
from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/ostream:40,
from /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/iostream:41,
from <source>:1:
/opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/type_traits:2235:12: note: 'template<bool _Cond, class _Iftrue, class _Iffalse> struct std::conditional' declared here
2235 |     struct conditional
|            ^~~~~~~~~~~
<source>:18:73: error: expected initializer before '<' token
18 | constexpr auto check(const T& val, Fn&& fn) -> typename std::conditional<fn(val), std::tuple<>, std::tuple<T>>::type {
|                                                                         ^
<source>: In instantiation of 'filter_tuple<std::tuple<<lambda(auto:16, auto:17)>, int, int, double, const char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <lambda(const T&)> >(const std::tuple<<lambda(auto:16, auto:17)>, int, int, double, const char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, <lambda(const T&)>&&)::<lambda(std::index_sequence<Is ...>)> [with long unsigned int ...Is = {0, 1, 2, 3, 4, 5}; std::index_sequence<Is ...> = std::integer_sequence<long unsigned int, 0, 1, 2, 3, 4, 5>]':
<source>:30:6:   required from 'constexpr auto filter_tuple(const T&, Fn&&) [with T = std::tuple<<lambda(auto:16, auto:17)>, int, int, double, const char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >; Fn = <lambda(const T&)>]'
<source>:54:38:   required from here
<source>:29:29: error: 'check' was not declared in this scope
29 |         std::tuple_cat(check(std::get<Is>(tpl), filter_fn)...);
|                        ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:54:6: error: deduced type 'void' for 'tpl_type_filtered' is incomplete
54 | auto tpl_type_filtered = filter_tuple(tpl, []<typename T>(const T&) constexpr -> bool { return std::is_integral_v<T>; } );
|      ^~~~~~~~~~~~~~~~~

我已经把lambda声明为constexpr了,但编译器还是不认可它的constexpr调用,不知道该怎么修正这个问题,希望能得到帮助。

备注:内容来源于stack exchange,提问作者glades

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 09:38:55