为什么我可以为除self之外的每个类创建强制转换运算符

时间:2012-07-20 14:15:42

标签: c++

struct B 
{

};

struct A
{
    operator A&() const;
    operator B&() const;
};


int main()
{
    const A a;
    B& br = a;
    A& ar = a;  
}

为什么我可以为B&创建强制转换操作符,但不能创建A&

可能没有多大意义(可以用它来擦除const修饰符,如例),但它至少不一致!

3 个答案:

答案 0 :(得分:4)

你不能这样做,因为它被明确禁止。 N3290§12.3.2声明:

  

调用这些函数   转换功能。不能指定返回类型。如果转换函数是成员函数,则   转换函数的类型(8.3.5)是“不返回convert-type-id的参数的函数”。 :一种   转换函数永远不会用于将(可能是cv限定的)对象转换为(可能是cv-qualified)   相同的对象类型(或对它的引用),到该类型的(可能是cv限定的)基类(或对它的引用)   it),或(可能是cv-qualified)void。

(强调我的)

这将在注释中进一步讨论:

  

这些转换被视为标准转换,用于重载解析(13.3.3.1,13.3.3.1.4)和   因此初始化(8.5)和显式强制转换(5.2.9)。

这解释了这个决定 - 它会过多地干扰内置机制。 (收益不大)。

如果你真的想要来自const对象的非const,那么唯一明智的做法是使用复制构造函数构建一个新实例。

作为一种解决方法,您可以引入轻量级中介(如智能指针):

struct B {};

struct A {};

namespace {
  B b_inst;
  A a_inst;
}

struct A_wrapper {
  A& inst;
  // This is perfectly fine: const alters the reference, not what it refers to
  operator A&() const { return inst; }
  operator B&() const { return b_inst; }
  A_wrapper() : inst(a_inst) {}
};

int main() {
  const A_wrapper a;
  B& br = a;
  A& ar = a;
}

但实际上,想要在第一时间做到这一点看起来就像代码味道。

答案 1 :(得分:3)

执行此操作的正确方法是使用const_cast

例如,

#include <iostream>
using namespace std;

void f(int* p) {
  cout << *p << endl;
}

int main(void) {
  const int a = 10;
  const int* b = &a;

  // Function f() expects int*, not const int*
  //   f(b);
  int* c = const_cast<int*>(b);
  f(c);

  // Lvalue is const
  //  *b = 20;

  // Undefined behavior
  //  *c = 30;

  int a1 = 40;
  const int* b1 = &a1;
  int* c1 = const_cast<int*>(b1);

  // Integer a1, the object referred to by c1, has
  // not been declared const
  *c1 = 50;

  return 0;
}

答案 2 :(得分:3)

声明转换为对self的引用并不是格式错误。您的问题出现在初始化参考时。由于引用的类型和初始化表达式的类型相同,引用为bound directly,因此永远不会考虑用户定义的转换运算符。因此,正常的转换规则适用,而const转换会使代码格式错误。

无论如何,你正在做的事情基本上是要求自己在脚下射击。如果您不喜欢constness请勿使用。如果你一直这样做,它永远不会打扰你,但它不会让你成为新朋友。