Partial specialization syntax confusion - c++

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.

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.

Inherit while using base template identifiers

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...

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.

c++ template casting

I'm a little lost in how to cast templates. I have a function foo which takes a parameter of type ParamVector<double>*. I would like to pass in a ParamVector<float>*, and I can't figure out how to overload the casting operator for my ParamVector class, and Google isn't helping me that much. Does anyone have an example of how to do this? Thanks.
EDIT: Adding some code, sorry I'm an idiot and didn't phrase the original question well at all;
template<class T> class ParamVector
{
public:
vector <T> gnome;
vector <T> data_params;
}
template<class T> class ParamVectorConsumer
{
public:
ParamVector<T> test;
}
ParamVector<float> tester;
ParamVectorConsumer<double> cons;
cons.ParamVector = tester
will fail to compile. I would like to know how to write it so that I can cast the float version of tester to a ParamVector double. Thanks
EDIT2: Casting was the wrong word. I don't mind writing extra code, I just need to know how to get this to be accepted by the compiler so that I can write some sort of conversion code.
I'm not sure but maybe you need some like this:
template< typename TypeT >
struct ParamVector
{
template < typename NewTypeT >
operator ParamVector< NewTypeT >()
{
ParamVector< NewTypeT > result;
// do some converion things
return result;
}
template< typename NewTypeT >
ParamVector( const ParamVector< NewTypeT > &rhs )
{
// convert
}
template < typename NewTypeT >
ParamVector& operator=( const ParamVector< NewTypeT > &rhs )
{
// do some conversion thigns
return *this;
}
};
ParamVector< double > d1;
ParamVector< float > f1;
f1 = d1;
You can choose use conversion operator or operator= - I've provided both in my example.
Well, you can't. Each different actual template parameter, makes an entirely new class, which has no* relation inheritance relation with any any other class, with a diffent actual argument, made from that template.
No relationship. Well, except that each provides the same interface, so that inside a template you can handle then the same.
But neither the static types or the dynamic types have any relation.
Let me drop back here, and explain.
When I declare a pointer to classtype, like
Foo fp*;
fp has what we call a static type, of pointer-to Foo. If class Bar is a subclass of Foo, and I point fp at new Bar:
fp = new Bar1();
then we say that the object pointed to by fp has the dynamic type of Bar.
if Bar2 also publicly derives from Foo, I can do this:
fp = new Bar2();
and without ever even knowing what fp points to, I can call virtual methods declared in Foo, and have the compiler make sure that the method defined in he dynamic type pointed to is what's called.
For a template< typename T > struct Baz { void doSomething(); };
Baz<int> and Baz<float> are two entirely different class types, with no relationship.
The only "relationship" is that I can call doSomething() on both, but since the static types have no relationship, if I have a Baz<int> bi*, I can't point it to a Baz<float>. Not even with a cast. The compiler has no way to "translate" a call to the Baz doSotheing method into a call to a Baz::doSomething() method. That's because there is no "Baz method", there is no Baz, there are ony Baz<int>s and Baz<float>s, and Baz<whatevers>, but there's no common parent. Baz is not a class, Baz is a template, a set of instructions about how to make a class if and only if we have a T parameter that's bound to an actual type (or to a constant).
Now there is one way I can treat those Bazes alike: in a template, they present the same interface, and the compiler, if it knows what kind of Baz we're really dealing with, can make a static call to that method (or a static access of a member variable).
But a template is not code, a template is meta-code, the instructions of how to synthesize a class. A "call" in a template is not a call,it's an instruction of how to write the code to make a call.
So. That was long winded and confusing. Outside of a template definition, there is no relationship between a ParamVector and aParamVector. So your assignment can't work.
Well. Almost.
Actually, with partial application of templates, you can write a template function which gives a "recipe" of how to transform a Paramvector<T> to a ParamVector<U>. Notice the T and the U. If you can write code to turn any kind of ParamVector, regardless of actual template parameter into any other kind of ParamVector, you can package that up as a partially applied template, and the compiler will add that function to, for example, ParamVector.
That probably involves making a ParamVector<U>, and transforming each T in the ParamVector<T> into a U to put in the ParamVector<U>. Which still won't let you asign to a ParamConsumer<T>.
So maybe you want to have both templates and inheritance. In that case, you can same that all ParamVectors regardless of type inherit from some non-template class. And then there would be a relationship between ParamVectors, they'd all be sibling subclasses of that base class.
Notice that when you do an implicit cast, what the compiler can do without your help (I mean, without additional code) is just reference-upcast. That means that, seeing the object as a reference (for cast purposes only, the nature of the object doesn't change of course), it can look at it as one of its ancestors. When you have two template instances, none of them is an ancestor of the other (neither they are necessarily in the same hierarchy).
After trying that, the compiler looks for cast operators, constructors, etc. At this stage, probably a temporary object needs to be created, except when you're doing attribution and there's an attribution operator that fits.
One solution to your problem would be to use a conversion constructor:
template<class T> class ParamVector
{
public:
vector <T> gnome;
vector <T> data_params;
ParamVector()
{
}
template <class T2> ParamVector(const ParamVector<T2> &source)
{
gnome.reserve(source.gnome.size());
copy(source.gnome.begin(), source.gnome.end(), gnome.begin());
data_params.reserve(source.data_params.size());
copy(source.data_params.begin(), source.data_params.end(), data_params.begin());
}
};
This would create a temporary object whenever you use an instance of the template and other is required. Not a good solution if you're dealing with large containers, the overhead isn't acceptable. Also, if you pass a template instance to a function that requires not an object but a reference, the compiler won't call the conversion constructor automatically (you have to do an explicit call).
You are lost because you can't do it - the two types are completely different. Whenever you come across the need for a cast in your code, you should examine both your code and your design very closely - one or both is probably wrong.
You can't do this with a direct cast because double and float are completly different sizes. Doubles are going to be 64 bits while floats are 32. A pointer forced to cast from a
ParamVector<float>
to
ParamVector<double>
is going to misinterpret the data and give you garbage. You may want to google "pointer aliasing" or just learn more about pointers in general to see how this isn't going to work.
Think about it for a second you have one array that is a bunch of 64 bit values with fields layed out like this
0 => abcdabcd12341234
1 => abcdabcd12341234
If you force this to be interpreted as an array of 32 bit values, its going to not be interpreted correctly. You may or may not get something like
0 => abcdabcd
1 => 12341234
2 => abcdabcd
3 => abcdabcd
or it could be switched so that the 12341234's come first, or something stranger due to how the word ordering works out.
You mentioned "template casting" in your headline, so I'll presume that ParamVector is a templated type. That means that foo could be templated as well, and that would solve your problem.
template <typename T>
void foo(ParamVector<T> const& data)
{
}
You can't cast templates like this because the types are unrelated.
However, you can add a conversion function, such as:
(Your code wasn't really complete, so I can post complete code either. Hopefully you will get the idea.)
template<class T> class ParamVectorConsumer
{
public:
ParamVector<T> test;
template<T2> ParamVectorConsumer<T2> convert()
{
ParamVectorConsumer<T2> ret;
ret = this->...
}