'const' 关键字改变语义

moo*_*ose 0 c++ constants

我在 C++ 中尝试了今天的 leetcode 挑战。你必须在二叉树中找到表亲。这是我的代码。

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

class Solution {
public:
    bool isCousins(TreeNode* root, int x, int y) {
        this->x = x;
        this->y = y;
        return visit(overloaded{
            [](const bool& r) { 
                return r; 
            },
            [](const optional<int>& r) { 
                return false; 
            }
        }, helper(root));
    }

private:
    int x;
    int y;

    variant<const bool, optional<int>> helper(TreeNode* node) {
        if (node == nullptr) {
            return variant<const bool, optional<int>>((optional<int>()));
        }
        else if (node->val == x) {
            return variant<const bool, optional<int>>(optional<int>(0));
        }
        else if (node->val == y) {
            return variant<const bool, optional<int>>(optional<int>(0));
        }
        else {
            auto l = helper(node -> left);
            auto r = helper(node -> right);
            return visit(overloaded{
                [](const bool& l, optional<int>& r) {
                    assert(!r.has_value());
                    return variant<const bool, optional<int>>(l); 
                },
                [](optional<int>& l, const bool& r) {
                    assert(!l.has_value());
                    return variant<const bool, optional<int>>(r); 
                },
                [](optional<int> l, optional<int> r) {
                    if (l.has_value() && r.has_value()) {
                        return variant<const bool, optional<int>>(*l > 0 && *l == *r);
                    }
                    else if (l.has_value()) { 
                        ++*l;
                        return variant<const bool, optional<int>>(l); 
                    }
                    else if (r.has_value()) { 
                        ++*r;
                        return variant<const bool, optional<int>>(r); 
                    }
                    else {
                        return variant<const bool, optional<int>>((optional<int>())); 
                    }
                }
            }, l, r);
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

一个证明我的问题的测试用例是

[1,3,2,null,null,7,4,null,null,5,6,null,8,null,9]
8
9
Run Code Online (Sandbox Code Playgroud)

上面的代码运行并成功完成。但是,如果我删除const第 10 行 ( [](bool& r) {)中的单个关键字,则会返回不同(不正确)的答案。const是为了编译时安全,所以不应该影响语义,但我想const重载会发生一些奇怪的事情吗?到底是怎么回事?

可能相关:也打破我的心智模式,如果代替宣布lr在线路34,35,我直接将它们作为参数来访问(即return visit(overloaded{..}, helper(node->left), helper(node->right),它也失败)。我再次希望这对语义没有影响。

cig*_*ien 5

const在这种情况下删除 会更改代码的含义,方法是更改​​在重载解析中选择的函数。

考虑以下重载集和调用:

void f(int const &) { std::cout << "i"; }
void f(bool) { std::cout << "b"; }

int main()
{
    int const i = 42;
    f(i); // prints i
    f(42); // prints i
}
Run Code Online (Sandbox Code Playgroud)

两者都调用第一个函数(如预期),因为 aint const &绑定到 a int const,以及int&&(临时的int)。

但是,如果我们删除const重载集的第一个函数中的 ,并进行相同的调用:

void f(int &) { std::cout << "i"; }
void f(bool) { std::cout << "b"; }

int main()
{
    int const i = 42;
    f(i); // prints b
    f(42); // prints b
}
Run Code Online (Sandbox Code Playgroud)

未选择第一个函数,因为int &, 无法绑定到int const。但是, abool可以绑定到int const, (在隐式转换之后),并调用第二个函数。类似地, anint &不能绑定到 a int&&,但可以绑定到 a bool,因此它调用第二个函数。

同样的推理适用于您的示例,但我删除了variant, 和自定义重载集,因为它简化了情况,而不会改变根本问题。