C++ C++;从按顺序执行的其他constexpr lambda创建lambda可以';Don’我不是康斯特普
假设我想创建一个lambda,它按如下顺序执行其他lambda:C++ C++;从按顺序执行的其他constexpr lambda创建lambda可以';Don’我不是康斯特普,c++,lambda,tuples,constexpr,C++,Lambda,Tuples,Constexpr,假设我想创建一个lambda,它按如下顺序执行其他lambda: constexpr auto some_func{[]() { // do something }}; constexpr auto some_other_func{[]() { // do something else }}; constexpr auto funcs_tuple = std::tuple(some_func, some_other_func); constexpr auto combined_fun
constexpr auto some_func{[]() {
// do something
}};
constexpr auto some_other_func{[]() {
// do something else
}};
constexpr auto funcs_tuple = std::tuple(some_func, some_other_func);
constexpr auto combined_funcs = do_funcs(funcs_tuple);
combined_funcs();
template <typename... Funcs>
constexpr auto make_do_funcs(Funcs&&... fs) {
const auto funcs = std::tuple(std::forward<Funcs>(fs)...);
return do_funcs(funcs);
}
template <typename Func, typename... Funcs>
constexpr auto do_funcs(Func&& f, Funcs&&... fs) {
return [f = std::forward<Func>(f), ... fs = std::forward<Funcs>(fs)] {
f();
if constexpr (sizeof...(fs) > 0) {
do_funcs(fs...);
}
};
}
我已将do_funcs
函数实现为:
template <std::size_t Idx = 0, typename Tuple>
constexpr auto do_funcs(const Tuple& tup) {
return [&]() {
if constexpr (Idx < std::tuple_size_v<Tuple>) {
const auto f = std::get<Idx>(tup);
f();
do_funcs<Idx + 1>(tup)();
}
};
}
我还想创建一个helper函数,它接受lambda的参数包,并将其作为元组分派给do_funcs
函数,如下所示:
constexpr auto some_func{[]() {
// do something
}};
constexpr auto some_other_func{[]() {
// do something else
}};
constexpr auto funcs_tuple = std::tuple(some_func, some_other_func);
constexpr auto combined_funcs = do_funcs(funcs_tuple);
combined_funcs();
template <typename... Funcs>
constexpr auto make_do_funcs(Funcs&&... fs) {
const auto funcs = std::tuple(std::forward<Funcs>(fs)...);
return do_funcs(funcs);
}
template <typename Func, typename... Funcs>
constexpr auto do_funcs(Func&& f, Funcs&&... fs) {
return [f = std::forward<Func>(f), ... fs = std::forward<Funcs>(fs)] {
f();
if constexpr (sizeof...(fs) > 0) {
do_funcs(fs...);
}
};
}
模板
constexpr自动生成函数(函数&&…fs){
const auto funcs=std::tuple(std::forward(fs)…);
返回do_funcs(funcs);
}
我使用元组而不是其他类似方法的原因如下:
constexpr auto some_func{[]() {
// do something
}};
constexpr auto some_other_func{[]() {
// do something else
}};
constexpr auto funcs_tuple = std::tuple(some_func, some_other_func);
constexpr auto combined_funcs = do_funcs(funcs_tuple);
combined_funcs();
template <typename... Funcs>
constexpr auto make_do_funcs(Funcs&&... fs) {
const auto funcs = std::tuple(std::forward<Funcs>(fs)...);
return do_funcs(funcs);
}
template <typename Func, typename... Funcs>
constexpr auto do_funcs(Func&& f, Funcs&&... fs) {
return [f = std::forward<Func>(f), ... fs = std::forward<Funcs>(fs)] {
f();
if constexpr (sizeof...(fs) > 0) {
do_funcs(fs...);
}
};
}
模板
constexpr auto do_funcs(Func&&f,funcs&&fs){
返回[f=std::forward(f),…fs=std::forward(fs)]{
f();
如果constexpr(sizeof…(fs)>0){
do_funcs(fs…);
}
};
}
这是因为“完美捕获”是C++20的一项功能,需要针对C++17使用元组进行变通
为了进一步参考,我尝试为我的组合解析器库制作一个实用工具“解析器”,它在需要时执行一些其他解析器来创建更复杂的解析器。简单的
std::apply()
(折叠逗号操作符)怎么样
#include <iostream>
#include <tuple>
int main()
{
auto some_func_1{[]() { std::cout << "1" << std::endl; }};
auto some_func_2{[]() { std::cout << "2" << std::endl; }};
auto funcs_tuple = std::tuple{some_func_1, some_func_2};
auto do_funcs
= [](auto const & tpl)
{ std::apply([](auto ... fn){ (fn(), ...); }, tpl); };
do_funcs(funcs_tuple);
}
我使用自己的helper结构作为lambda
template <typename... Funcs>
struct do_funcs {
constexpr do_funcs(Funcs... fs) : funcs{fs...} {}
void operator()() const {
do_rest();
}
template <std::size_t Idx = 0>
void do_rest() const {
if constexpr (Idx < sizeof...(Funcs)) {
const auto f = std::get<Idx>(funcs);
f();
do_rest<Idx + 1>();
}
}
const std::tuple<Funcs...> funcs;
};
模板
结构do_funcs{
constexpr do_funcs(funcs…fs):funcs{fs…}{
void运算符()()常量{
不要休息;
}
模板
void do_rest()常量{
if constexpr(Idx
这使得问题中给出的示例是constepr。生成
funcs\u tuple
static
。因为它是constexpr
,所以这不会真正改变代码的运行方式,因为对任何函数的所有调用都应该始终到达相同的funcs\u tuple
值。(我想,如果您出于某种原因获取了它的地址,则会有区别。)但是,它确实引用了funcs\u tuple
constexpr
,因为现在有一个对象由constexpr
变量表示,而不是每次调用函数都有一个对象
请注意,这不适用于constexpr
函数。谢天谢地,如果封闭函数是constexpr
,那么变量就不需要是。也就是说,你可以两者都做
void func() { // func not constexpr
static constexpr auto funcs_tuple = ...;
constexpr auto combined_funcs = do_funcs(funcs_tuple);
}
或
//喜欢这个问题
模板
constexpr自动生成函数(函数&&…fs){
//函数不是constexpr或static;使函数仍然是constexpr
const auto funcs=std::tuple(std::forward(fs)…);
返回do_funcs(funcs)(;//或其他任何内容
//注意:不能返回do_funcs(funcs),因为这将是一个悬空引用
//你原来的make_do__函数被破坏了
}
我不知道你的意思。为什么不能声明组合函数constexpr
?你有错误吗?还有,你的意思是不是combined_funcs()代码>而不是do_funcs()代码>?@cigien是,我在Ok上使用clang(主干)得到“错误:constexpr变量'combined_funcs'必须由常量表达式初始化,注意:对'funcs_tuple'的引用不是常量表达式”。把这个错误加在问题上。这个链接也很有用。我正在制作一个组合解析器库,需要一些组合解析器的方法来创建一个新的解析器,按顺序运行给定的解析器,创建一个更复杂的解析器。我将不得不编写一组结合其他解析器的解析器,或者甚至结合其他解析器本身的解析器,所以我想把这样做简化为一个简单的函数调用。这个解决方案比问题中的解决方案好吗?这一个似乎也在复制元组。问题解决方案的问题是,lambda每次递归调用时都会复制元组,而这一个只复制一次,然后在递归调用期间将其保存在结构中。请参阅链接,其中显示了我最初的解决方案使用不同的索引对每个调用do_funcs
创建一个新的lambda专门化和一个新的元组副本。是我的新解决方案,它只创建一个副本。这似乎是迄今为止最好的解决方案。很抱歉吹毛求疵,但我看到这个解决方案的唯一问题是在constexpr函数中不能有静态变量,所以如果我想创建一个constexpr helper函数,比如说make_do_funcs
,它接受一个funcs
参数包,并从中创建一个元组,然后将其分派到do_funcs
我不能使用此解决方案。我会在这个问题上加上这个要求。我不认为我完全理解你的意思。这是我理想的目标。你是不是建议我把make_do__funcs
non-constexpr?编辑:对不起,我发错了link@RikusHoney对不起,我也遇到了,发表了评论,意识到它不起作用,删除了它,现在我才意识到我是对的,你的代码是错的<代码>make_do_funcs
返回悬空引用<代码>函数
一旦返回,就会消失。它并没有引用funcs
,而是使它不是一个常量表达式。如果你把它放在返回值中,它是悬空的。它已损坏,无论是否为constexpr
,都无法工作。我想你需要一份副本。我仍然会使用我的答案,因为这是我最终想要实现的,但你的答案实际上回答了我提出的问题。谢谢你的努力。