C++ 如何使用'UnaryPredicate'lambda'筛选constexpr'std::array'?
给定一个C++ 如何使用'UnaryPredicate'lambda'筛选constexpr'std::array'?,c++,templates,c++17,constexpr,C++,Templates,C++17,Constexpr,给定一个constepr std::array和一个UnaryPredicate pred,我如何筛选数组以返回一个新的constepr std::array,它的所有元素都满足pred(e) structfoo{ int f1; int f2; }; 静态constexpr std::数组arr{foo{1,1},{2,2},{3,3},{4,4},{5,5}; int main(){ //将导致{foo{1,1}、{2,2}、{4,4}、{5,5} constexpr auto filter
constepr std::array
和一个UnaryPredicate pred
,我如何筛选数组以返回一个新的constepr std::array
,它的所有元素都满足pred(e)
structfoo{
int f1;
int f2;
};
静态constexpr std::数组arr{foo{1,1},{2,2},{3,3},{4,4},{5,5};
int main(){
//将导致{foo{1,1}、{2,2}、{4,4}、{5,5}
constexpr auto filterd=filter_数组(arr,[](const foo&f){返回f.f1!=3;})
返回0;
}
< /代码> 这肯定是,<强>依赖类型< /强>,在当前C++中,依赖于<强>值<强>的类型是不可能的。您不能仅通过函数参数来决定结果类型std::array
的大小M
,这意味着M
必须是模板参数
因此,您必须通过constepr
函数count\u if
为结果类型提供一个额外的模板参数M
,然后确定每个元素的值:
模板
constexpr T get_element_helper(T const*arr、Pred和&Pred){
return pred(arr[0])?arr[0]:获取元素辅助对象(arr+1,pred);
}
模板
constexpr T get_element_helper(T const*arr、Pred和&Pred){
返回pred(arr[0])?获取元素辅助对象(arr+1,pred):获取元素辅助对象(arr+1,pred);
}
模板
constexpr std::数组过滤器\u数组\u辅助程序(std::数组const&arr、Pred&Pred、std::索引\u序列*){
返回{get_element_helper(arr.data(),pred)…};
}
模板
constepr std::数组过滤器\u数组(std::数组const&arr、Pred&Pred){
返回过滤器\数组\助手(arr,std::forward(pred),(std::make\ u index \ u sequence*)nullptr);
}
模板
constexpr size\u t count\u if\u helper(std::array const&arr,Pred&Pred,std::index\u sequence*){
返回((大小)(bool)pred(arr[Is])+…);
}
模板
constexpr size\u t count\u if(标准::数组const&arr、Pred&Pred){
如果帮助器(arr,std::forward(pred),(std::make_index_sequence*)nullptr)返回计数;
};
int main(){
constexpr std::数组a={0,1,2,3,4};
constexpr auto pred=[](int a){返回一个%2==0;};
constexpr auto b=filter_array(a,pred);//std::array{0,2,4}
}
因为中有很多算法,所以get\u元素\u助手是我缺少的,非常聪明!顺便说一句,c++17允许在constexpr函数中使用局部变量和for循环,count\u如果
实际上可以在单个函数中实现。@zoujyjs你说得对。只是我已经习惯了。无论如何,感谢C++17!你会使用c++20吗?由于许多算法,如std::remove_if
现在是constepr
。但是arr
是常量,不能修改,只能生成一个新数组。我尝试了remove\u if
并且编译器抱怨“您无法分配一个常量变量”`No,我们可以在lambda中复制arr
并修改它,然后使用constepr std::pair
接受修改后的arr
,并对应大小,但是gcc-10的当前版本也有一些。是的,汇编代码确实编译成了期望的结果。在我的情况下使用它有点激进,因为它甚至没有在最新的msvc 2019中编译。无论如何,这有助于使用最先进的标准。
struct foo {
int f1;
int f2;
};
static constexpr std::array<foo, 5> arr{ foo{1,1}, {2,2}, {3,3}, {4,4}, {5,5} };
int main() {
// will result in { foo{1,1}, {2,2}, {4,4}, {5,5} }
constexpr auto filterd = filter_array(arr, [](const foo& f) {return f.f1 != 3;})
return 0;
}
#include <algorithm>
#include <array>
struct foo {
int f1;
int f2;
bool operator==(const foo&) const = default;
};
constexpr static std::array arr{foo{1,1}, foo{2,2}, foo{3,3}, foo{4,4}, foo{5,5}};
constexpr auto filter_array(auto pred) {
constexpr auto p = [=] {
auto res = arr;
auto size = std::distance(res.begin(), std::remove_if(res.begin(), res.end(), pred));
return std::pair{res, size};
}();
constexpr auto res = p.first;
constexpr auto size = p.second;
return [=]<auto... Is>(std::index_sequence<Is...>) {
return std::array{res[Is]...};
}(std::make_index_sequence<size>{});
}
int main() {
// will result in { foo{1,1}, {2,2}, {4,4}, {5,5} }
constexpr auto filterd = filter_array([](const foo& f) { return f.f1 == 3; });
static_assert(filterd == std::array{foo{1,1}, foo{2,2}, foo{4,4}, foo{5,5}});
}