I have this class SmallInt
that should represent a positive integer value in the range 0-255
-inclusive:
struct SmallInt{
explicit SmallInt(int x = 0) : iVal_( !(x < 0 || x > 255) ? x :
throw std::runtime_error(std::to_string(x) + ": value outbounds!")){}
operator int&() { return iVal_; }
int iVal_;
};
int main(){
try{
SmallInt smi(7);
cout << smi << '\n';
cout << smi + 5 << '\n'; // 7 + 5 = 12
cout << smi + 5.88 << '\n'; // 7.0 + 5.88 = 12.88
smi = 33; // error: constructor is explicit
smi.operator int&() = 33;
cout << smi << '\n';
}
catch(std::runtime_error const& re){
std::cout << re.what() << '\n';
}
}
What matters me is: why can I assign to smi
explicitly calling operator int&
: smi.operator int&() = 33
but not implicitly: smi = 33;
?
The first expression (smi = 33;
) complains about the constructor SmallInt(int)
begin explicit
; I know that but I have the conversion operator that returns a modifiable plain lvalue. So in other words why in such an implicit assignment is the constructor preferred to the conversion operator?
[over.match.oper]/4 For the built-in assignment operators, conversions of the left operand are restricted as follows:
...
(4.2) — no user-defined conversions are applied to the left operand to achieve a type match with the left-most parameter of a built-in candidate.
Thus (int &)smi = 33
interpretation is explicitly prohibited from consideration by the standard.