Search code examples
c++c++11templatesoperator-overloadingclass-template

Overloaded operator= to switch between template types


I have a template class that multiple classes are inheriting from to basically make some user-friendly builders, hiding the functions that are not required on different builders, while following DRY.

However, I'm having trouble switching between the builder types. I'd prefer to use the operator= to switch without hassle and have the following code.

template<class T> class BuilderFunctions
{
protected:
    std::string text;

public:
    template<class Other>
    BuilderFunctions<T>& operator=(const Other& other);
};

template <class T>
template <class Other>
BuilderFunctions<T>& BuilderFunctions<T>::operator=(const Other& other)
{
    // yes, I need same object protection
    text = other.text;
    return *this;
}

Classes


class BuilderGenericList : public BuilderFunctions<BuilderGenericList> 
{
public:
    BuilderGenericList() = default;
};

// Build configuration details
class BuilderRootList : public BuilderFunctions<BuilderRootList>
{
private:
    // I'll delete the functions I don't want accessed here

public:
    BuilderRootList() = default;
};

Code that says no

// Real world you'd build the root first and switch out to another builder or be using a prototype to seed another builder
BuilderRootList cmakeRoot;
BuilderGenericList list;

// Separate to make sure it's not trying to use cop constructor
list = cmakeRoot;

Except I might be doing something I shouldn't be doing with template classes, although others seem to have success with templates in the operators, so assume possible, and I'm making some kind of mistake.


More info: The error I get is:

Error   C2679   binary '=': no operator found which takes a right-hand operand 
of type 'BuilderRootList' (or there is no acceptable conversion)

So It's definitely looking for my operator=, it's just not generating one from the template


Solution

  • When you do the template inheritance, you have to be explicit in case of base classes members. More read:

    In your case, the members text, and operator=, can be brought via using declaration.

    class BuilderGenericList : public BuilderFunctions<BuilderGenericList> 
    {
    public:
        BuilderGenericList() = default;
        using BuilderFunctions<BuilderGenericList>::text;
        using BuilderFunctions<BuilderGenericList>::operator=;
        // ... so on, other members from base if needed!
    };
    
    // Build configuration details
    class BuilderRootList : public BuilderFunctions<BuilderRootList>
    {
    public:
        BuilderRootList() = default;
        using BuilderFunctions<BuilderRootList>::text;
        using BuilderFunctions<BuilderRootList>::operator=;
        // ... so on, other members from base if needed!
    };
    

    Live Demo

    Note that, this will make the memberusing BuilderFunctions<BuilderGenericList>::text public, if this is not what wanted, consider the suggestion by @Jarod42 in other answer.