How to reduce redundant code when adding new c++0x rvalue reference operator overloads

后端 未结 4 1491
不思量自难忘°
不思量自难忘° 2020-12-08 05:29

I am adding new operator overloads to take advantage of c++0x rvalue references, and I feel like I\'m producing a lot of redundant code.

I have a class, tree

4条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-08 05:45

    First, I don't see why operator+ would modify the arguments at all (isn't this a typical immutable binary tree implementation), so there'd be no difference between r-value and l-value reference. But let's assume that the subtrees have a pointer up to the parent or something like that.

    From the usage example you showed, it looks like there's an implicit conversion from double to tree. In that case, your "cast and forward" cases aren't needed, the compiler will find the user-defined conversion.

    Don't the non-move overloads end up making a new instance to go into the new tree? If so, I think you can write three of your remaining four cases as forwarders.

    tree operator +(tree&& a, tree&& b); // core case
    tree operator +(tree   a, tree   b) { return std::move(a) + std::move(b); }
    tree operator +(tree   a, tree&& b) { return std::move(a) + std::move(b); }
    tree operator +(tree&& a, tree   b) { return std::move(a) + std::move(b); }
    

    Of course, you can use a macro to help generate the three (or seven) forwarding versions of each operator.

    EDIT: if those calls are ambiguous or resolve to recursion, how about:

    tree add_core(tree&& a, tree&& b);
    tree operator +(tree&& a, tree&& b) { return add_core(std::move(a), std::move(b)); }
    tree operator +(tree   a, tree   b) { return add_core(std::move(a), std::move(b)); }
    tree operator +(tree   a, tree&& b) { return add_core(std::move(a), std::move(b)); }
    tree operator +(tree&& a, tree   b) { return add_core(std::move(a), std::move(b)); }
    

    EDIT: repro of the operator failure to use implicit conversions:

    #include 
    
    template
    class tree;
    
    template tree add(tree a, tree b)
    {
        std::cout << "added!" << std::endl << std::endl;
        return tree();
    }
    
    template tree operator +(tree   a, tree   b) { return add(a, b); }
    
    template
    class tree
    {
    public:
        tree() { }
        tree(const tree& t) { std::cout << "copy!" << std::endl; }
        tree(double val)    { std::cout << "double" << std::endl; }
        friend tree operator +(tree a, tree b);
    };
    
    int main()
    {
        tree(1.0) + 2.0;
        return 0;
    }
    

    And version without templates where the implicit conversion works:

    #include 
    
    class tree
    {
    public:
        tree() { }
        tree(const tree& t) { std::cout << "copy!" << std::endl; }
        tree(double val)    { std::cout << "double" << std::endl; }
    friend tree operator +(tree a, tree b);
    };
    
    tree add(tree a, tree b)
    {
        std::cout << "added!" << std::endl << std::endl;
        return tree();
    }
    
    tree operator +(tree a, tree b) { return add(a, b); }
    
    int main()
    {
        tree(1.0) + 2.0;
        return 0;
    }
    

提交回复
热议问题