C++ 当隐式转换发生时,对象是否会失去常量?

C++ 当隐式转换发生时,对象是否会失去常量?,c++,object,constants,implicit-conversion,C++,Object,Constants,Implicit Conversion,我做了一个小实验,但我不明白结果 class C { public: operator int() const { std::cout << "I'm const" << std::endl;} operator int(){ std::cout << "I'm not const" << std::endl;} }; void f(int){}; int main() { f(C()); } g(C())输出“I取常数” 一个临

我做了一个小实验,但我不明白结果

class C {
public:
  operator int() const { std::cout << "I'm const" << std::endl;}
  operator int(){ std::cout << "I'm not const" << std::endl;}
};

void f(int){};

int main()
{
  f(C());
}
g(C())输出“I取常数”


一个临时变量不是常数:

C();  // not const
如果您想经常引用它,请将其转换为:

f(static_cast<const C&>(C()));
f(static_cast(C());
关键是,其成员函数(此处为转换运算符)被调用的对象不是常量。这与转换的结果无关

结果实际上也不需要是常数。假设我们添加另一个类:

class D { };

class C {
  // ...
  operator D() { return D(); }
};

int main()
{
  D d;
  static_cast<D>(C()) = d;      // OK: assign d to the result of the conversion
  // static_cast<int>(C()) = 6; // Error: left-hand side is not an lvalue
}
D类{};
C类{
// ...
运算符D(){return D();}
};
int main()
{
D;
static_cast(C())=d;//确定:将d分配给转换结果
//static_cast(C())=6;//错误:左侧不是左值
}

这可能会让你大吃一惊,但这是完全合法的C++:

class C { } ;
int main()
  {
  C d ;
  C() = d ;
  }

看看证据。所以
C()
是左值。

你为什么说“输”?你为什么一开始就希望有人成为警察?好吧。所以没有任何东西默认为const,但是为什么g的行为与C::operator int()不同呢?不,与constness无关,只与左值/右值有关。您不能分配给右值,右值是转换为int的结果。我正在编辑以添加此示例。好的。但是为什么在调用g(C())时使用g(C const&)而在调用int(C())时使用int(C&)呢?@Ragnar:这是一个关于右值的大谜团。我不知道为什么,但您可以对右值调用任何您喜欢的非常量方法,但它不能作为非常量引用传递到用户定义的函数中。我自己也觉得这个问题非常复杂和奇怪,我从来没有看到过令人满意的解释。@Ragnar:temporary只绑定到
C const&
,但它本身并不是常数。这仅仅是一个语言设计决策(这是非常聪明的),但是如果必须的话,您可以自由地抛弃常量并修改对象,因为临时对象本身并不是不变的。还请注意,临时值将很高兴地绑定到可变的
C&
“是左值”错误。这是一个右值。也许你相信左值的意思是“可以在左边”?事实并非如此。左值就是左值。它“毫无意义”。这是一组(大部分是任意的)规则。
C()
是一种“显式类型转换(函数表示法)”[expr.type.conv](它不将任何内容转换为某些内容)。“表达式
T()
(…)创建指定类型的prvalue”“创建类类型的临时值(…)创建prvalue的转换”[class.temporary]在历史分类中,它只是一个右值。无论如何,表达式引用了一个类对象,它有一个地址,可以有一个名为…“Lvalue意味着Lvalue”的成员函数。这意味着对于Lvalue,rvalue没有一个可爱的定义。。。确切的定义涉及一长串案例,描述中有一长串特定属性。如果你想对左值做一个简短的定义:“你可以把操作符的地址应用到它上面”,它很短,很可爱,对于原语类型和用户定义的类型都是错误的。“我不认为C()符合简单类型说明符typename说明符中的任何一个”真的???你认为[expr.type.conv]适用于什么?
class C { } ;
int main()
  {
  C d ;
  C() = d ;
  }