众所周知,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);
答案 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来避免。