Inherit while using base template identifiers - c++

I have two templates A and B both with the same template types. Always, A inherits from B, but it always chooses the same template for B as A itself uses.
This is fine in and of itself, but this requires me to write the template type twice. Is it possible to somehow typedef the type in A and refer to the generic typedef name when inheriting from the subclass?
Below is some example code that does not compile but should give a clear idea of what I want to do:
// #1
template <typename T>
struct A
{
typename T type;
// class details here
};
// #2
template <typename T>
struct B
{
// class details here
};
// #3
template <>
struct A<int>
: B<type> // Compiler complains here (type not defined)
//: B<A::type> // Compiler complains here (type not defined)
// I could write ": B<int>" instead, but this is repitition I want to avoid
{
// class specialization details here
};
I'm open for alternative solutions. The reason this is important to me is that I have a large laundry list of code like that of #3 and I want to reduce duplication (to avoid bugs).

Two different specializations of the same template are completely unrelated types*, so you cannot use A<>::type from the base template inside the specialization A<int>. Even if you define type inside the A<int> specialization, it won't be available until the class is defined, which happens after the list of inheritance.
You could and you should use : B<int> there. It is no more repetition than B<type>, and makes it explicit that A<int> inherits from B<int>, something that is not immediately visible if you go through indirections.
Another thing that kind of bugs me from your design is that A<> (the generic one) does not have any relationship with B<>, but A<int> inherits from B<int>. While the language allows for completely unrelated behavior in specializations, that might be surprising to other programmers, when they can pass objects of A<T> to functions taking B<T> for some T, but not for others...
What is the actual problem that you want to get solved?
* The implication of this is that an specialization does not provide special behavior (i.e. only the bits that differ from the base) but all the behavior of that type. If you only mean to override part of the behavior you should consider other alternatives, like refactoring A<T> (generic) into a base so that A<int> (or other specializations) can borrow the implementation. Or if the changes in behavior are small you might be able to just specialize some of the member functions...

Related

template enforcing unnecessary restriction

Say an Object has a templated TYPE (for a very good reason)
template <typename T> class Object {
};
I want an Object to be able to contain an array of subobjects.
template <typename T> class Object {
vector< Object<T>* > subobjects;
};
However, the subobjects CAN BE OF ANY TYPE. That is, a subobject can be an Object of a different T than it’s parent.
The language is enforcing a restriction that doesn’t need to be there. How do I fix this?
A template is a type-factory. Object<int> and Object<double> are unrelated types.
Object<int> generates one type, and Object<double> generates a different type.
If you want these two types to be related, you can make them related.
struct IObject {
virtual ~IObject() {}
// common interface
};
then
template<class T>
struct Object<T>:IObject {
std::vector<IObject*> subObjects;
};
now your Object<T> has subobjects. All the code knows (statically) is that they are IObjects.
Now, if you want the type T to be runtime determined, you could use std::any (this has type safety issues, sort of; it is "brittle" in that the reader needs to know the exact type that went into it) or std::variant<double, int, std::string> (but here you have to name all of the supported types).
Basically, you are probably using a round peg and a square hole.
You have a problem. You thought templates where the solution. You found a problem with your solution. You looked for a way to make templates work.
The language is enforcing a restriction that doesn’t need to be there. How do I fix this?
The language isn't enforcing anything. You wrote a template with one type parameter, so that parameter can only take one value at a time.
However, the subobjects CAN BE OF ANY TYPE. That is, a subobject can be an Object of a different T than it’s parent.
If you mean each Object<T> can have children of a single different type U != T, just write
template <typename T, typename U> class Object {
vector< Object<U>* > subobjects;
};
If you mean each object can have children of a variety of instantiations, you either need some form of type erasure (eg. std::any), or polymorphism.
In either case, you need to give some thought to what you're going to do with these things you don't know the concrete type of. How will you use them? This is the information needed to choose the appropriate mechanism.
Using #WayneVanderLinde's comment:
struct Object{
vector<Object*> subobjects;
};
template<typename T> struct TObject : public Object {};
you can now create
TObject<int> i;
TObject<double>* d = new TObject<double>();
i.subobjects.push_back( d );

Is std::iterator inherints from a sort of auto_ptr?

I am a beginner in STL. I'm trying to code a toystl to learn STL. When I code about iterator, I'm puzzled if I should code a simple auto_ptr first and inherint from it.
I wrote a base class called iterator. And now it works like this,
struct iterator{};
template <class T>
struct vector_itorater: public toystl::iterator<toystl::random_access_iterator_tag, T>{};
If i need another base class works like a "auto_ptr"? just like this
// firstly define a sort of auto_ptr as base class
struct auto_ptr{};
// secondly inherint from auto_ptr
template <class T>
struct vector_itorater: public auto_ptr{};
Does this work? Or does STL do it like this?
I think you mixed up runtime polymorphy and compile time polymorphy. When the compiler instantiates a template, it cares about its visible interface of the concrete object. It does not care if this object has a inheritance relationship with other classes, it will pass as long as the concrete object can be used within the concrete context.
template <class C>
void foo(const C& bar)
{
// at the time of writing we don't know anything of C,
// only that it has a callable baz member (either a
// member function or a member with a call operator).
// This works, since the compiler knows the exact type
// during template instantiation, but we don't have to
// care in advance.
bar.baz();
}
struct X
{
void baz() const;
};
void grml()
{
X x;
// The compiler fills in X as the template type
// parameter for us. So the compiler creates a
// void foo<X>(const X&) function for us.
foo(x);
}
In this example when the compiler sees the template, it has no clue how this template will be called later. Only once the template gets instantiated (used), the compiler then will check if the passed type is suitable for this template.
Here it is not needed to have a common base class to derive every possible implementation from. The STL uses templates in order to avoid to use such base classes, since they give you a burden on your design later, and if you have virtual members in the base to override, you can get a serious performance penalty.

Is the only way to "polymorphically" declare a member of a non-specialized template type, by defining a base class?

Suppose we have a templated class,
template<typename Type>
class Container {};
Of course, we can't do this:
struct Foo
{
Container _container;
}
But what if we wanted to do something like it? Is the only way to do this, to define a base class,
class ContainerBase {};
template<typename Type>
class Container : public ContainerBase {};
and store a pointer, like below?
struct Foo
{
ContainerBase* _container;
}
It's simple enough, but it feels weird to have to add a base class solely for that reason, when it seems the compiler should have enough information to imply a set of related specializations. Of course, regardless _container needs to be a pointer, else Foo couldn't resolve to a static size, but
struct Foo
{
Container* _container;
}
doesn't work either.
it seems the compiler should have enough information to imply a set of related specializations.
Nope. Template specializations are totally unrelated except in name, and the name of a type has essentially no bearing on runtime operation. Specializations of a given template usually share a (mostly) common interface, but they could just as well be completely different.
Adding a base class is essential if you want to relate between the specializations. And if they share so much in common, factoring that functionality into the base is a pretty great idea.

Inheritance and templates in C++

I have the following problem with inheritance and templates:
class Base {};
class Deriv : public Base {};
template <class T> class X{};
void f(X<Base>& inst) {}
int main()
{
X<Base> xb;
f(xb);
X<Deriv> xd;
f(xd);
return 0;
}
The program doesn't compile because there is not relation between X<Base> and X<Deriv>. Nevertheless I think it should be possible to do everything that can be done with X<Base> also with X<Deriv>. Is there anything that I could do other than copying the function body of f to a new function void g(X<Deriv>& inst)?
You could just continue using templates:
template<class T>
void f(X<T>& inst) {}
will work for both X<Base> and X<Derived>.
The compiler might duplicate the code (if it is not smart enough), but you don't have to.
Why do you think they should be related? Consider the following:
template<typename T>
class X;
template<>
class X<Base> {
int x;
};
template<>
class X<Deriv> {
double d;
};
They're definitely not interchangeable. So no, there is no relation between those classes and you can't pass one to a function expecting the other. You'll have to do something like make both types inherit from another common type that exposes the interface you need.
Regarding your comment, you can use type traits and static_assert to do what you would do in Java:
template<typename T>
void f(X<T>& inst) {
static_assert(std::is_base_of(Base, T)::value, "Template type must subclass Base");
// body of function...
}
If you need such functionality, then you must template on the type- or overload, as you have said. Alternatively, you might explicitly specialize X such that X<Derived> : X<Base>.
Different instantiations of a template are unrelated types, even if the instantiating template arguments are related. That is, X<A> is not related to X<B> regardless of what the relationship between A and B might be.
Now as of what can be done, it depends on what your template actually is. In some cases you can provide conversions so that the X<Derived> can be converted to a X<Base> for a particular operation. Another alternative is modifying your function to be able to take any X<T> for which T derives from Base (this can be done by creating a template and using SFINAE to disallow calling it with Ts that don't derive from Base. Again, depending on what your template is, you might be able to offer access to the underlying type, in which case the function could take a reference to Base (consider shared_ptr or unique_ptr with the .get() method)
Without a description of what you actually want to get done it is impossible to provide a good alternative.
It depends. Consider the case where X is std::shared_ptr. It would break type safety if std::shared_ptr<Derived> was derived from std::shared_ptr<Base>, but instead there is an implicit value conversion.
However, since you’re passing by reference to non-const, such a value conversion will not help you you directly.
Other possibilities include inheriting from a common interface, and templating your function.

Partial specialization syntax confusion

To define a specialization that is used for every Vector of pointers and only for
Vectors of pointers, we need a partial specialization:
template <class T> class Vector <T *> : private Vector<void *> {
public:
typedef Vector<void*> Base;
Vector(): Base() {}
explicit Vector(int i) : Base(i ) {}
T *& elem(int i ) { return static_cast <T *&> (Base::elem(i)); }
T *& opeator[](int i) { return static_cast <T *&>(Base::operator[](i )); }
//...
};
This definition has me in a tizzy. This is related to partial specialization but i don't understand the syntax. private Vector<void *> definition part looks like a parent class to me.
Why not specify Vector <void *> in template <class T> class Vector <void *>.
It would be great if anybody can breakdown the definition part. (sorry if its too much to ask)
Forget about the inheritance, which has nothing to do with the problem at hand.
Partial specialization means that you make a new template from an existing one which is more specialized, but still generic, by matching a more restrictive pattern. The general pattern of your example is like this:
template <typename T> class Foo; // primary template
template <typename U> class Foo<U*>; // partial specialization
template <> class Foo<fool>; // full specialization
The first line is the primary template and matches everything that is not matched by a more specialized form. The third line defines an actual type (not a template!) Foo<fool> (for some given type fool). The middle line, on the other hand, is still a template, but it only matches a type of the form T = U *, i.e. a pointer:
Foo<char> x; // uses primary template with T = char
Foo<fool> y; // uses full specialization (nothing to be matched)
Foo<int*> z; // uses partial specialization, matching U = int
About the Vector<void*>: It just turns out that the author chooses to define the partially-specialized Vector<U*> as deriving from a fixed class Vector<void*> (which would have to be fully specialized elsewhere).
Your question is about template specialization, and that's what's going on here.
This is a template class definition of a Vector<T> being specialized for a pointer type T. Presumably, you've defined the Vector<T> template elsewhere, so this code is only specializing it for the circumstance where T is a pointer. Hence the Vector<T*>.
Since it is a specialization, the Vector<T*> derives from the Vector 'base-template', which is a Vector<void *>. The other code, which isn't detailed in your example, would handle specifics of working with a pointer type as the contained data.
Basically, this is making the members of Vector<Ptr>, for any pointer type, forward to Vector<void*> (using a combination of inheritance and explicit base calls plus casting). This prevents the compiler from making many identical versions of the same code, differing only by the pointer type, possibly saving space in the final executable (although most linkers are smart enough to combine identical functions, see for instance "COMDAT folding")
This is problematic according to the Standard because the pointers don't have the same alignment restrictions. Not all object pointers necessarily have the same size in a conforming implementation. In fact, I'm very surprised that the compiler accepts static_cast<T*&>(a_void_ptr) at all. Static casting between void* and T* is allowed of course, but this deals with reference-to-pointer types, which are unrelated. It should require reinterpret_cast.
It seems that the author of the code wants to exploit the fact that the code for different pointer types is identical. It is probably just a premature optimization to reduce code size, or "code bloat". The idea is most likely that each new pointer type will only add a layer of static_cast to the void pointer code.