C++:转换运算符重载和引用

gex*_*ide 9 c++ casting reference operator-overloading

C++允许通过创建一个operator T()where T我们想要转换为的类型来重载类型转换.

现在,此功能如何与引用一起使用?例如:

struct Y{ int i; };

struct X{
    Y y;

    operator Y() const { return y; }
};
Run Code Online (Sandbox Code Playgroud)

在这里,我们可以强制X转换Y包含的内容Y.但是,如果我们想要对某个Y参考进行强制转换呢?例如,C++允许我们这样做:

struct X{
    Y y;

    operator Y&(){ return y; }
    operator const Y&() const { return y; }
};
Run Code Online (Sandbox Code Playgroud)

现在,我们可以X转换为Y引用或const引用(也适用于a const X).

第一个和第二个例子的语义有什么不同吗?如果我想允许转换为引用,最好的方法是什么?

我可以想象,即使我operator T()没有任何写入&,C++可能允许转换通过引用返回结果(即,operator T&()当我指定时它可能以某种方式添加隐式方法operator T()).

例如,我想要以下代码工作:

int main(){
    X x;
    Y& y = x; // y now references the y inside x
    y.i = 5;
    std::cout << x.y.i << std::endl; // Should print 5 now
}
Run Code Online (Sandbox Code Playgroud)

实现这一目标的最简单方法是什么?

Nia*_*all 7

声明 a 是否意味着operator T()强制转换总是T按值返回 a ?

这意味着转换运算符将按 指定的方式返回T。无论是引用、指针还是值。例如,给定某种类型(根据OP)Y

operator Y();
operator Y&();
operator Y*();
Run Code Online (Sandbox Code Playgroud)

是否所有(带有 cv 限定的变体)有效的用户定义的转换。要用作Y参考,您需要将其作为参考返回。

所以,是的,转换为T不是引用的 a 意味着返回类型是一个值。这与一般的转换语义一致- 返回一个值。

第一个和第二个例子的语义有什么不同吗?

是的,存在语义差异。它们与具有引用与值返回类型的其他方法具有相同的语义差异。它们的不同之处就像以下两种方法的不同一样;

Y get_y_value();
Y& get_y_ref();
Run Code Online (Sandbox Code Playgroud)

笔记

在同一个类中混合operator Y();operator Y&();可能会导致不明确的重载(至少 clang 抱怨这一点,但 gcc 似乎很乐意将两者混合)。

我不会在这里就哪一个更好发表意见,因为您的情况细节尚不清楚。但一般来说,在实现用户定义的转换时,请始终考虑通常如何执行强制转换以及可能更频繁地返回右值。explicit随着 C++11 的出现,也支持它们;出于同样的原因,构造函数是explicit(或者如果特别需要则不是)。


Rob*_*ahy 6

是否声明operator T()演员总是返回一个T值?

是.

返回类型的转换运算符隐式正是它们转换为的内容.

[...]转换函数的类型是"不返回convert-type-id的参数的函数".

§12.3.2[class.conv.fct]


Dra*_*rax 5

使用铿锵++:

#include <iostream>

class   test
{
public:
  test(int n) : nb{n} {}

public:
  operator int() { return nb; }

  private:
    int nb;
};

int     main(void)
{
  test  t{42};

  int x = t;

  int& ref = t;   // error: non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'test'
  int&& rref = t; // compiles fine

  std::cout << x << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

这表明您确实返回了一个临时的新值。

帮助您在两种情况之间进行选择的真正问题是:您是否想让人们修改您的内部成员(返回引用)以及该成员的复制成本是否昂贵(使用 const 引用而不是值)?