【问题标题】:separate handlers lvalue and rvalue [] operators单独的处理程序 lvalue 和 rvalue [] 运算符
【发布时间】:2018-03-15 05:24:25
【问题描述】:

有没有办法让 [] 运算符在左值和右值上下文中的处理方式不同?

示例代码:

include <stdio.h>

class test {
public:
  unsigned a;
  unsigned const & operator [](unsigned const idx) const;
  unsigned & operator [](unsigned const idx);
};

unsigned const & test::operator [](unsigned const idx) const {
  printf("const [%u] called\n", idx);
  return a;
}

unsigned & test::operator [](unsigned const idx) {
  printf("non-const [%u] called\n", idx);
  return a;
}

int main() {
  test t;
  unsigned a;
  a = 0;
  printf("a = %u\n", a);
  t[0] = a;
  printf("stored a to t[0]; a = %u\n", a);
  a = t[0];
  printf("read a from t[0]; a = %u\n", a);
}

t[0] = a; 有 lvalue-context [] 运算符,a = t[0]; 有 rvalue-context [] 运算符,但它们都是通过非常量函数处理的。我还尝试声明 unsigned const &amp; test::operator [](unsigned const idx) 方法,但它没有编译并说不允许这种重载。有没有办法(我需要它)通过 t[0]=a;a=t[0]; 的不同处理程序来处理 [] 运算符?

请不要将此标记为与C++ Operator Overloading [ ] for lvalue and rvalue 重复,因为此问题不一样,即使看起来相似。

添加了可能也相关的简化代码: 包括

class test {
public:
  unsigned a;
  unsigned const & operator [](unsigned const idx) const;
  /*unsigned & operator [](unsigned const idx);*/
};

unsigned const & test::operator [](unsigned const idx) const {
  printf("const [%u] called\n", idx);
  return a;
}

/*unsigned & test::operator [](unsigned const idx) {
  printf("non-const [%u] called\n", idx);
  return a;
}*/

int main() {
  test t;
  unsigned a;
  a = t[0];
  printf("read a from t[0]; a = %u\n", a);
}

我注释掉了非常量运算符 [],删除了对 t[0] 的写入,现在它编译并使用了 [] 所需的方法。但是一旦我取消注释非常量,它就会开始使用它并忽略前一个。换句话说,问题是:有没有办法在所有可能的地方让 const 优先于非 const ?

【问题讨论】:

  • 阅读ref-qualified functions cppref 链接实际上可能不是最好的资源
  • 在这两种情况下,t 肯定是一个左值。您似乎在询问区分对t 的读写访问权限。在这种情况下,您可能想要使用代理 - 请参阅 stackoverflow.com/questions/30806786/…
  • 在 C++ 中,“左值”和“右值”并不真正意味着更传统的“赋值左侧”和“赋值右侧”。
  • 不幸的是,引用限定函数没有帮助 - 如果存在,它仍然对这两种情况使用左值一。至于代理类——我知道有可能,但对于这样一个简单的问题,它看起来编码太多了:(。是的,它是对t 的读写访问,但从编译器的角度来看,它应该是读取的——只有对[]返回的值的读写访问。

标签: c++ operator-overloading


【解决方案1】:

不是和是的。

不,上下文不能更改 C++ 中运算符或函数的返回类型。

是的,您可以使用伪引用来伪造它。

伪引用是重载operator =(T const&amp;)&amp;&amp;operator T()&amp;&amp; 的对象。

struct pr_unsigned { // lazy name, do better
  unsigned* target;
  void operator=(unsigned const& in)&&{ *target=in; }
  operator unsigned()&&{ return *target; }
  pr_unsigned(pr_unsigned&&)=delete;
};

这有点像玩具,但是:

pr_unsigned test::operator [](unsigned const idx) { return {&a}; }

我们现在为test[2]=3;foo=test[0]; 提供了不同的代码路径。

这远非完美的模拟; auto x = test[2]; 做错事了。但这并不可怕。

您可以将test*unsigned idx 存储在pr_unsigned 中,并在向/从分配元素时在test 上运行任意代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多