struct B
{
};
struct A
{
operator A&() const;
operator B&() const;
};
int main()
{
const A a;
B& br = a;
A& ar = a;
}
为什么我可以创建强制转换运算符 to B&
,但不能创建A&
.
可能它没有多大意义(可以用它来擦除const
修饰符,如示例),但它至少不一致!
struct B
{
};
struct A
{
operator A&() const;
operator B&() const;
};
int main()
{
const A a;
B& br = a;
A& ar = a;
}
为什么我可以创建强制转换运算符 to B&
,但不能创建A&
.
可能它没有多大意义(可以用它来擦除const
修饰符,如示例),但它至少不一致!
你不能这样做,因为它被明确禁止。N3290 § 12.3.2 规定:
此类函数称为转换函数。不能指定返回类型。如果转换函数是成员函数,则转换函数的类型(8.3.5)是“不带参数返回转换类型ID的函数”。转换函数永远不会用于将(可能是 cv 限定的)对象转换为(可能是 cv 限定的)相同的对象类型(或对它的引用),转换为该类型的(可能是 cv 限定的)基类(或对它的引用)或(可能是 cv 限定的)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;
}
但实际上,一开始就想做这件事看起来像是代码味道。
正确的方法是使用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;
}
声明转换为对 self 的引用并不是错误的。您的问题出现在您的引用被初始化的时候。由于引用的类型和初始化表达式的类型相同,因此bound directly
永远不会考虑引用和您的用户定义的转换运算符。因此,正常的转换规则适用,而 const 转换使代码格式错误。
无论如何,您所做的基本上是要求自己中弹。如果您不喜欢constness
,请不要使用它。如果你一直这样做,它永远不会打扰你,但它不会让你结交新朋友。