I have the following code, which, in my opinion, should not compile:
(In a class Vector
(not the std::vector
, but a Vector
that I defined myself)):
Vector operator*(double factor)
{
// some element-wise multiplication here
return factor;
}
I am defining this operator to return a Vector
, but inside the method i return a double
.
I also have not defined any implicit conversion operators inside the class.
I would think that this is clearly not valid, but gcc happily compiles this, without any complaint at all.
My first reflex is to file a defect-report to gcc, but I thought I would ask here before..
Am I missing something here that would explain why this code is considered valid by the compiler?
(In case it's relevant, c++-standard is set to c++17)
Some more Info on the Vector
class: (namely, I include all declared constructors and operators, as other, named functions should not contribute to this issue):
class Vector {
public:
Vector(std::vector<double> values);
Vector(size_t dimension, double value);
Vector(size_t dimension);
void operator*=(double factor);
void operator*=(Vector const& factor);
friend Vector operator-(Vector const& a, Vector const& b);
friend Vector operator+(Vector const& a, Vector const& b);
friend Vector operator*(Vector const& a, Vector const& b);
Vector operator*(double factor);
double& operator[](size_t i);
friend std::ostream& operator<<(std::ostream& stream, Vector const& v);
}
Basing this answer on received comments:
Non-explicit conversion-operators are not the only way in which a return-value that initially has the wrong type may "become" the type needed for the function-signature. The constructor
Vector(size_t dimension);
Takes one numerical value as an argument, which itself is not a double
, but a long unsigned int
, but a double
can be converted into that.
So what happens is that the double factor
is first converted into a long unsigned int
and then an implicit construction of Vector
, using the constructor Vector(size_t dimension);
happens.
The object that is the result of this construction is then returned.
Therefore, this is valid code in the sense of not breaking language-rules, the compiler is definitely not doing anything wrong here.
If this behaviour is not wanted, the constructor in question should be marked explicit
like this:
explicit Vector(size_t dimension);
If there were multiple constructors taking one argument of a type into which a double
can be converted, or whose first arguments fulfill that requirement with all other arguments being optional, for example:
Vector(int a, char b = 'c');
they would have to be marked explicit
as well, but in that case it is likely that the compiler would complain, because it could not deduce which constructor to call.