struct B
{
};
struct A
{
operator A&() const;
operator B&() const;
};
int main()
{
const A a;
B& br = a;
A& ar = a;
}
为什么我可以为B&
创建强制转换操作符,但不能创建A&
。
可能没有多大意义(可以用它来擦除const
修饰符,如例),但它至少不一致!
答案 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
,请勿使用。如果你一直这样做,它永远不会打扰你,但它不会让你成为新朋友。