Reputation: 67175
I have code similar to the following:
class CIntColumn : public CColumn
{
public:
CIntColumn(LPCTSTR pszName)
{
}
// Etc.
}
class CTextColumn : public CColumn
{
public:
CTextColumn(LPCTSTR pszName, int nMaxLength)
{
}
// Etc.
}
template<typename BASE_TYPE>
CNullableColumn : public BASE_TYPE
{
public:
// Questions about code that goes here
}
class CNullableIntColumn : public CNullableColumn<CIntColumn>
{
public:
CNullableIntColumn(LPCTSTR pszName)
: CNullableColumn<CIntColumn>(pszName)
{
}
}
class CNullableTextColumn : public CNullableColumn<CTextColumn>
{
public:
CNullableTextColumn(LPCTSTR pszName, int nMaxLength)
: CNullableColumn<CTextColumn>(pszName, nMaxLength)
{
}
}
As is, this code won't compile because CNullableIntColumn
needs to pass a single argument to the base class, and CNullableTextColumn
needs to pass two arguments to the base class.
Is there any trick to modify my CNullableColumn<>
template class so it supports both cases? Ideally, I could use some sort of conditional compilation but C++ doesn't seem to support they kind that would be needed here.
Upvotes: 0
Views: 466
Reputation: 67175
Building on what Xirema seemed to be originally suggesting, the following appears to work.
template <typename BASE_TYPE>
class CNullableColumn : public BASE_TYPE
{
protected:
template<typename T1>
CNullableColumn<BASE_TYPE>(T1 pszName)
: BASE_TYPE(pszName)
{
}
template<typename T1, typename T2>
CNullableColumn<BASE_TYPE>(T1 pszName, T2 nMaxLength)
: BASE_TYPE(pszName, nMaxLength)
{
}
}
Upvotes: 1
Reputation: 20386
You need a generic forwarding constructor that will take any number of arguments and pass them to the base class for CNullableColumn
:
template<typename BASE_TYPE>
class CNullableColumn : public BASE_TYPE {
public:
template<typename ... Args>
CNullableColumn(Args && ... args) :
BASE_TYPE(std::forward<Args>(args)...) {}
};
This should cause all your later uses of CNullableTextColumn
and CNullableIntColumn
to forward their arguments correctly to their roots.
So if you know in advance that each type will only ever have exactly 1 argument, except for one or two specific types that will have two, you might prefer template specialization instead:
template<typename BASE_TYPE>
class CNullableColumn : public BASE_TYPE {
public:
CNullableColumn(LPCTSTR pszName) :
BASE_TYPE(pszName) {}
};
//Specialization
template<>
class CNullableColumn<CTextColumn> : public CTextColumn {
public:
CNullableColumn(LPCTSTR pszName, int maxLength) :
CTextColumn(pszName, maxLength) {}
};
//Could create other specializations for other types with different #s of arguments, if needed
Now, the disadvantage of Template Specialization is that you have to be clever in your implementation to avoid duplicating code. But it'll at least elegantly solve the problem you're trying to deal with without just turning everything into a Varargs nightmare.
Upvotes: 1