Question

Here's a short template class example which I want my compiler to reject:

struct Vector {
  Vector(float a, float b, float c): x(a), y(b), z(c) {}
  float x, y, z;
};

template <typename T>
class Field {
public:
  const T doSomething() const;
};

template <typename T>
const T Field<T>::doSomething() const {
  T out(0);
  return out;
}

template <>
const Vector Field<Vector>::doSomething() const {
  return Vector(1,2,3);
}

template <>
const float Field<float>::doSomething() const {
  return 0.0f;
}

int main() {
  Field<float> g;
  Field<Vector> h;
  g.doSomething();

  // This should be illegal!
  h.doSomething() = Vector(3,4,5);
}

The compiler successfully throws an error! However, let's pretend I have to compile with -Wall -Wextra, for which this code generates the warning:

main.cpp:25:41: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]

Ah, so you could remove the const qualifier on doSomething()'s return type, but that would pass my illegal line of code at the bottom. As a possible solution at least for my toy problem you can probably write the generic doSomething() to handle the primitive types and this warning is not generated, but say I have to specialize a primitive type. Is there a way to drop this warning short of altering the warning flags?

Was it helpful?

Solution

With C++11, you can restrict the assignment operator to lvalue references like this:

struct Vector {
  Vector(float a, float b, float c): x(a), y(b), z(c) {}
  float x, y, z;
  Vector& operator=(const Vector&) & = default;
};

Now you can drop the const from the return type:

template <>
Vector Field<Vector>::doSomething() const {
  return Vector(1,2,3);
}

and your statement is still an error:

error: no match for ‘operator=’ (operand types are ‘Vector’ and ‘Vector’)
   h.doSomething() = Vector(3,4,5);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top