从一次DEBUG体会modernCPP
今天写树形dp,用匿名函数出现了极其玄学的报错,modernCPP给我上了一课
note: 'solve()::<lambda(auto:23, int, int)>::~
()' is implicitly deleted because the default definition would be ill-formed 
源代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> edge[n + 1];
    std::vector<int> F(n + 1);
    std::vector<int> ind(n + 1);
    for (int u, v, i = 0; i < n - 1; i++) {
        std::cin >> u >> v;
        edge[u].emplace_back(v);
        edge[v].emplace_back(u);
        ind[u]++; ind[v]++;
    }
    auto dfs = [&](auto self, int x, int father) -> void {
        if (ind[x] == 1 && x != 1) {F[x] = 1; return ;}
        for (auto& to : edge[x]) if (to != father) {
            self(self, to, x);
            F[x] += F[to]; 
        }
        return ;
    };
    dfs(dfs, 1, 0);
    int q;
    std::cin >> q;
    while(q--) {
        int x, y;
        std::cin >> x >> y;
        std::cout << F[x] * F[y] << '\n';
    }
}
排查
由于报错是析构函数出错,比较难以排查,所以就枚举了所有情况,发现以下几种写法可以通过编译。
- 
声明 function类型std::function<void(int, int)> dfs = [&](int x, int father) -> void { if (ind[x] == 1 && x != 1) {F[x] = 1; return ;} for (auto& to : edge[x]) if (to != father) { dfs(to, x); F[x] += F[to]; } return ; };从声明类型后就可以通过编译我感觉是编译器在 auto 推断时出了错误,然而却并非如此。 
- 
注明捕获对象 auto dfs = [&ind, &edge, &F](auto self, int x, int father) -> void { if (ind[x] == 1 && x != 1) {F[x] = 1; return ;} for (auto& to : edge[x]) if (to != father) { self(self, to, x); F[x] += F[to]; ` } return ; };这里找出了真正的原因,自动捕获到了脏东西。 
解决
自动捕获到了什么脏东西?
对捕获对象逐一排查后,发现对于邻接表存图的 edge,把大小改成常量或者使用 vector 嵌套后就能通过编译。
这里涉及了 CPP 为了兼容 C 而留下的遗留问题
VLA虽然允许存在,但是modernCPP的接口没有义务再兼容VLA
改成嵌套 vector 后即可通过
void solve() {
    int n;
    std::cin >> n;
    std::vector<std::vector<int>> edge(n + 1, std::vector<int>());
    std::vector<int> F(n + 1);
    std::vector<int> ind(n + 1);
    for (int u, v, i = 0; i < n - 1; i++) {
        std::cin >> u >> v;
        edge[u].emplace_back(v);
        edge[v].emplace_back(u);
        ind[u]++; ind[v]++;
    }
    auto dfs = [&](auto self, int x, int father) -> void {
        if (ind[x] == 1 && x != 1) {F[x] = 1; return ;}
        for (auto& to : edge[x]) if (to != father) {
            self(self, to, x);
            F[x] += F[to]; 
        }
        return ;
    };
    dfs(dfs, 1, 0);
    int q;
    std::cin >> q;
    while(q--) {
        int x, y;
        std::cin >> x >> y;
        std::cout << F[x] * F[y] << '\n';
    }
}

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号