C++ C++;从按顺序执行的其他constexpr lambda创建lambda可以';Don’我不是康斯特普

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

假设我想创建一个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_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
,都无法工作。我想你需要一份副本。我仍然会使用我的答案,因为这是我最终想要实现的,但你的答案实际上回答了我提出的问题。谢谢你的努力。