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
CodePudding user response:
When you do the template inheritance, you have to be explicit in case of base classes members. More read:
- Why do I have to access template base class members through the this pointer?
- Derived template-class access to base-class member-data
- Accessing base member functions in class derived from template class
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!
};
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.
CodePudding user response:
BuilderFunctions<T1>
cannot access private
/protected
member of BuilderFunctions<T2>
(with T1
!= T2
): add accessor, or make them friend
.
in addition, you also have to put using for operator=
:
template<class T>
class BuilderFunctions
{
template <typename U> friend 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;
}
class BuilderGenericList : public BuilderFunctions<int>{
public:
using BuilderFunctions<int>::operator=;
BuilderGenericList() = default;
};
//Build configuration details
class BuilderRootList : public BuilderFunctions<float>
{
private:
//I'll delete the functions I don't want accessed here
public:
using BuilderFunctions<float>::operator=;
BuilderRootList() = default;
};