使用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
相关产品推荐
相关产品推荐

