链接运算符=对于只写对象 - 确定返回rhs而不是* this?

时间:2013-05-25 12:04:20

标签: c++ pointers operators

众所周知,operator=应该返回 const *this的引用以支持链接,但只有在*this 可以使用时才有效作为右值是有价值的。

编辑:很好,operator=应该返回非const引用(与int s一样),我的意思是*this需要

中的一个有意义的rhs

我正在通过C ++类ApiWrapper包装name = value setter函数的C API,operator[]返回一个带有重载Proxy的临时只写operator=,但API没有getter函数,因此Proxy实际上是只写的。

ApiWrapper x;
x["a"] = x["b"] = 42;  // x["b"] = 42;      fine:  consumes 42, returns *this
                       // x["a"] = x["b"];  error: x["b"] does not have the value

在我看来,如果我从rhs返回*this而不是operator=的const引用,则链接可以正常工作。从概念上讲(代理样板代码遗漏):

struct Proxy {
    template <typename T>
    T const& operator=(T const& rhs) const
    {
        ...         // pass rhs to the API but don't store it
        return rhs; // return rhs, not *this
    }
};

ApiWrapper x;
x["a"] = x["b"] = 42;  // x["b"] = 42;   fine: consumes and returns 42
                       // x["a"] = 42;   fine: consumes and returns 42

这让我很怀疑。将const引用返回rhs而不是*this是否有任何奇怪的副作用?我唯一能想到的是,我无法在像(x["a"] = 42).doSomething()这样的表达式中使用它,但我的Proxy无法支持任何类似的东西,因为它是只写的。或者最好是不允许链接(例如通过返回void)?

编辑:即使Proxy不是类似值,我认为支持作业是有道理的,它允许语法糖如:

// this:                          // rather than:
ApiWrapper w;                     API * ptr = make_api_instance();
w["name"] = "Batman";             api_set_str(ptr, "name", "Batman");
w["age"]  = 42;                   api_set_int(ptr, "age", 42);
w["pi"]   = 3.14;                 api_set_double(ptr, "pi", 3.14);

2 个答案:

答案 0 :(得分:1)

我认为最干净的解决方案是坚持标准习语。如果您以通常的方式使代理类可以复制构造和可复制分配,这应该可行。像这样:

struct Proxy
{
    Proxy(Proxy const & rhs)
    : // ...
    {
        // copy internal state of rhs
    }

    Proxy & operator=(Proxy const & rhs)
    {
        // copy internal state of rhs
        return *this;
    }

    template <typename T>
    Proxy & operator=(T const & rhs)
    {
        // ... perform T-specific operations ... #1
        return *this;
    }
};

另一个好处是,无论在#1的第一次分配必须执行的“通用逻辑”,都不需要在每次后续分配中重复。

答案 1 :(得分:0)

我认为你的方法是有道理的。只是为了检查我是否正确理解你的问题,结构看起来像这样:

struct Proxy {
    template <typename T>
    T const& operator=(T const& rhs) const
    {
        send_to_abi(rhs);
        return rhs;
    }
};

正如您所说,由于Proxy不会将rhs存储在任何地方,并且我假设不存在receive_from_abi函数,因此返回*this将不起作用 - 该数字将不会传播在这种情况下。正如评论所指出的那样,某些行为如(a=3)=3将无效,但这并不奇怪。

编辑:正如评论所指出的,如果rhs是临时性的,这种方法很危险。这可以通过返回副本来修复:

struct Proxy {
    template <typename T>
    T operator=(T const& rhs) const
    {
        send_to_abi(rhs);
        return rhs;
    }
};

这可能看起来很昂贵a["a"] = a["b"] = a["c"] = foo看起来会涉及3份副本。但是这些应该可以通过通用的编译器optmimization来避免。