Search code examples
c++gccoperator-overloadingimplicit-conversion

C++ accepts wrong return-type


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);
}

Solution

  • 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.