Create assignment operator in templated base class [duplicate]

1 week ago 8
ARTICLE AD BOX

The error is actually not about the assignment operator at all — it's about construction. The line:

cpp

PushConstant_Vec1 v = 4.5f;

is copy-initialization, which requires a constructor that accepts a float, not an assignment operator. The compiler is looking for:

cpp

PushConstant_Vec1(float) // doesn't exist

The operator= you defined would only be relevant for an already-constructed object, like:

cpp

PushConstant_Vec1 v; v = 4.5f; // this would work fine

The Inheritance Problem

Even if you added a converting constructor to the base class:

cpp

PushConstant(const T& value) : Value(value) {}

...it still wouldn't work for PushConstant_Vec1 v = 4.5f; because the error message is telling you exactly why:

"Conversion requires a second user-defined-conversion operator or constructor"

C++ only allows one implicit user-defined conversion in a chain. To construct PushConstant_Vec1 from float, the compiler would need to:

Convert float → PushConstant<float, vec1> (user-defined conversion #1)

Convert PushConstant<float, vec1> → PushConstant_Vec1 (user-defined conversion #2)

That's two hops, which C++ explicitly forbids implicitly.


Solutions

Option 1 — Inherit the base constructor with using (simplest)

cpp

struct PushConstant_Vec1 : public PushConstant<float, PushConstantType::vec1> { using PushConstant::PushConstant; // pulls in base constructors directly };

You still need a converting constructor in the base:

cpp

template<typename T, PushConstantType P> struct PushConstant { PushConstant() = default; PushConstant(const T& value) : Value(value) {} // add this PushConstant<T, P>& operator=(const T& value) { Value = value; return *this; } T Value {}; };

Now PushConstant_Vec1 v = 4.5f; works because the inherited constructor is treated as belonging to the derived class directly — no two-hop conversion needed.


Option 2 — Explicit constructor in the derived class

If you want the derived class to be self-contained:

cpp

struct PushConstant_Vec1 : public PushConstant<float, PushConstantType::vec1> { PushConstant_Vec1(float value) { Value = value; } };

More verbose but makes the intent very explicit.


Option 3 — Implicit conversion operator (alternative direction)

If you'd rather keep construction default and make the base class convertible, you can add an implicit conversion operator:

cpp

operator T() const { return Value; }

But this doesn't help with v = 4.5f construction — it goes the wrong direction (PushConstant → T, not T → PushConstant).


Recommendation

Option 1 with using PushConstant::PushConstant is the idiomatic modern C++ solution — it keeps the derived structs as bare-bones as you want while the base class owns all the logic cleanly.

Read Entire Article