为啥以下代码编译失败(C++ lambda问题)

Posted

技术标签:

【中文标题】为啥以下代码编译失败(C++ lambda问题)【英文标题】:Why does the following code failed to compile (C++ lambda problem)为什么以下代码编译失败(C++ lambda问题) 【发布时间】:2022-01-21 17:03:46 【问题描述】:

好吧,我正在编写一个函数,其中我在 C++ (GNU C++14) 中使用了递归 lambda。所以我尝试了y_combinator 方法,从main() 函数之外的声明开始(在此之前我使用过using namespace std;)。

#include <bits/stdc++.h>

using namespace std;

template<class Fun>
class y_combinator_result 
    Fun fun_;
public:
    template<class T>
    explicit y_combinator_result(T &&fun): fun_(forward<T>(fun)) 

    template<class ...Args>
    decltype(auto) operator()(Args &&...args) 
        return fun_(ref(*this), forward<Args>(args)...);
    
;

template<class Fun>
decltype(auto) y_combinator(Fun &&fun) 
    return y_combinator_result<decay_t<Fun>>(forward<Fun>(fun));


int main () 
    cin.tie(0)->sync_with_stdio(0);

    int N; cin >> N;
    vector<int> adj[N+1];
    for (int i = 0; i < N-1; i++) 
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    
    
    vector<int> d(N+1);
    auto dfs = y_combinator([&](auto dfs, int u, int p, int &r) 
        if (u == p) d[u] = 0;
        if (d[u] > d[r]) r = u;
        for (auto &v : adj[u]) 
            if (v != p) 
                d[v] = d[u]+1;
                dfs(v, u, r);
            
        
    );

现在我有一个简单易懂的问题要问你们:是什么让这个 lambda 函数甚至无法编译(这发生在主函数内部)?

问题是,当我试图编译它时,我收到了这个灾难性的消息:

test1.cpp: In function 'int main()':
test1.cpp:36:29: error: use of deleted function 'main()::<lambda(auto:1, int, int, int&)>::~<lambda>()'
   36 |     auto dfs = y_combinator([&](auto dfs, int u, int p, int &r) 
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   37 |         if (u == p) d[u] = 0;
      |         ~~~~~~~~~~~~~~~~~~~~~
   38 |         if (d[u] > d[r]) r = u;
      |         ~~~~~~~~~~~~~~~~~~~~~~~
   39 |         for (auto &v : adj[u]) 
      |         ~~~~~~~~~~~~~~~~~~~~~~~~
   40 |             if (v != p) 
      |             ~~~~~~~~~~~~~
   41 |                 d[v] = d[u]+1;
      |                 ~~~~~~~~~~~~~~
   42 |                 dfs(v, u, r);
      |                 ~~~~~~~~~~~~~
   43 |             
      |             ~
   44 |         
      |         ~
   45 |     );
      |     ~
test1.cpp:36:31: note: 'main()::<lambda(auto:1, int, int, int&)>::~<lambda>()' is implicitly deleted because the default definition would be ill-formed:
   36 |     auto dfs = y_combinator([&](auto dfs, int u, int p, int &r) 
      |                               ^

所以我尝试通过捕获 2 个向量名称 dadj 进行小修复

#include <bits/stdc++.h>

using namespace std;

template<class Fun>
class y_combinator_result 
    Fun fun_;
public:
    template<class T>
    explicit y_combinator_result(T &&fun): fun_(forward<T>(fun)) 

    template<class ...Args>
    decltype(auto) operator()(Args &&...args) 
        return fun_(ref(*this), forward<Args>(args)...);
    
;

template<class Fun>
decltype(auto) y_combinator(Fun &&fun) 
    return y_combinator_result<decay_t<Fun>>(forward<Fun>(fun));


int main () 
    cin.tie(0)->sync_with_stdio(0);

    int N; cin >> N;
    vector<int> adj[N+1];
    for (int i = 0; i < N-1; i++) 
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    
    
    vector<int> d(N+1);
    auto dfs = y_combinator([&d, &adj](auto dfs, int u, int p, int &r)  // I changed this line
        if (u == p) d[u] = 0;
        if (d[u] > d[r]) r = u;
        for (auto &v : adj[u]) 
            if (v != p) 
                d[v] = d[u]+1;
                dfs(v, u, r);
            
        
    );

并且程序按预期编译... 显然,从我的角度来看,有一个非常大的问题:为什么我使用[&amp;] 捕获main() 函数中所有内容的第一段代码失败了,但第二段代码有效?有什么办法可以解决这个问题,因为我不想花时间捕获变量...

P/s : 请原谅我的英语不好。我不是母语人士。

【问题讨论】:

@S.M.呃......在我的代码中,我总是将'vector'定义为'vt'。看,我已经在我的代码中评论过……(对不起,代码用于竞争性编程,所以我必须尽量节省时间) 我们可以在没有所有这些可怕的宏的情况下拥有一个 single minimal reproducible example。 @S.M.我注意到您使用 Clang 和 C++20 编译它,而我使用带有 c++14 的 GNU C++(如开头所述)。 【参考方案1】:

C++ 没有 VLA vector&lt;int&gt; adj[N+1];。使用此 VLA 会导致编译器错误。见Variable Length Array (VLA) in C++ compilers。

使vector&lt;int&gt; adj[N+1]; -> vector&lt;vector&lt;int&gt;&gt; adj(N+1); 使示例兼容。

【讨论】:

非常感谢。将其更改为vector&lt;vector&lt;int&gt;&gt; adj(N+1);,它工作得很好。再次感谢您的帮助,祝您有美好的一天!

以上是关于为啥以下代码编译失败(C++ lambda问题)的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的由 boost.python 和 c++ 头文件编译的 .so 文件失败了?

为啥编译器可以比普通函数更好地优化 lambda?

声明全局 lambda C++ 时出现问题 [重复]

为啥将 lambda 用于非类型模板参数时 gcc 会失败?

为啥在编译时不检查 lambda 返回类型?

为啥 g++ 和 MS Visual Studio C++ 执行以下代码的方式不同?