简体   繁体   English

'const' 关键字改变语义

[英]'const' keyword changing semantics

I attempted today's leetcode challenge in C++.我在 C++ 中尝试了今天的 leetcode 挑战 You have to find cousins in a binary tree.您必须在二叉树中找到表亲。 Here's my code.这是我的代码。

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);
        }
    }
};

A testcase that demonstrates my issue is一个证明我的问题的测试用例是

[1,3,2,null,null,7,4,null,null,5,6,null,8,null,9]
8
9

The code above runs and completes successfully.上面的代码运行并成功完成。 However, if I remove a single const keyword in line 10 ( [](bool& r) { ) then it returns a different (incorrect) answer.但是,如果我在第 10 行( [](bool& r) { )中删除了一个const关键字,那么它会返回一个不同的(不正确的)答案。 const is for compile-time safety, so shouldn't affect semantics, but I guess something strange is happening with const overloading? const是为了编译时安全,所以不应该影响语义,但我猜const重载会发生一些奇怪的事情? What's going on exactly?究竟是怎么回事?

Possibly related: it also breaks my mental model that if, instead of declaring l , r in lines 34,35, I pass them directly as arguments to visit (ie. return visit(overloaded{..}, helper(node->left), helper(node->right) ), it also fails. I would again expect that to have no effect on semantics. Possibly related: it also breaks my mental model that if, instead of declaring l , r in lines 34,35, I pass them directly as arguments to visit (ie. return visit(overloaded{..}, helper(node->left), helper(node->right) ), 它也失败了。我再次希望这对语义没有影响。

Removing the const in this case changes the meaning of the code, by changing which function is selected in overload resolution.在这种情况下删除const会更改代码的含义,通过更改在重载决议中选择的 function。

Consider the following overload set and call:考虑以下重载集和调用:

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
}

both call the first function (as expected), because a int const & binds to a int const , as well as int&& (a temporary int ).两者都调用第一个 function (如预期的那样),因为int const &绑定到int const以及int&& (临时int )。

However, if we remove the const in the first function of the overload set, and make the same call:但是,如果我们删除重载集的第一个 function 中的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
}

the first function is not selected, because an int & , cannot bind to a int const .第一个 function 没有被选中,因为int &不能绑定到int const However, a bool can bind to an int const , (after an implicit conversion), and it calls the second function.但是, bool可以绑定到int const (在隐式转换之后),并且它调用第二个 function。 Similarly, an int & cannot bind to a int&& , but a bool can, so it calls the second function.同样, int &不能绑定到int&& ,但bool可以,因此它调用第二个 function。

This same reasoning applies to your example, but I've removed the variant , and custom overload set, as it simplifies the situation, without changing the underlying problem.同样的推理也适用于您的示例,但是我删除了variant和自定义重载集,因为它简化了情况,而没有改变潜在的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM