templated recursive data types - c++

I have a recursive data type like this:
template<typename T>
struct SomeType {
std::map<T, SomeType<T>> mapping;
};
SomeType<int> foo;
This works fine, but replacing std::map with std::unordered_map results in a compile error due to an incomplete type. Am I (or gcc) making an error somewhere? or is this just part of the standard?
I would also like to have the internal container determined by a template parameter (like std::stack and std::queue), but I can't figure out a way to do it since that would require SomeType to already be defined.
Incomplete example:
template<typename T, typename C = std::map<T, SomeType<[???]>>>
struct SomeType {
C mapping;
};
SomeType<int, [???]> foo;
I know this can be done with runtime indirection, but that's not what I'm looking for.

Your class is incomplete anywhere before the final } of its definition. So the mapping member is using incomplete type SomeType in its type's template arguments.
The standard does not allow this, and it is pure luck that it works with some STL containers.
Your second questions falls under the same answer -- it is illegal to do that in the first place.

You cannot define a template with recursive default parameters for obvious reasons. You also cannot instantiate standard library container templates on incomplete types, because the standard says so (otherwise it's undefined behaviour). The usual PIMPL idiom may help, though:
#include <map>
#include <memory>
template <typename T> class SomeType
{
typedef std::map<T, SomeType<T>> map_type;
typedef std::unique_ptr<map_type> map_ptr;
map_ptr pimpl;
public:
SomeType() : pimpl(new map_type) { }
};

While you cannot use incomplete types with containers, you can do it with smart pointers.
And while you cannot create template types with undefined types parameters, you can use some tricks here:
template<typename T, template <typename U, typename V, typename... Args> class Container = std::unordered_map >
struct SomeType {
Container<T, std::unique_ptr<SomeType> > mapping;
};

Related

Using interfaces in C++ with STL containers [duplicate]

I am wondering if it is possible to convert a vector of derived class values to a vector of base class values. Specifically I want to be able to pass a vector of base class objects to a function whose formal parameters takes a vector of base class. It does not appear to be possible directly as the following code example produces an error (using g++):
#include <vector>
class A {
};
class B : public A {
};
void function(std::vector<A> objs) {
}
int main(int argc, char **argv) {
std::vector<B> objs_b;
objs_b.push_back(B());
function(objs_b);
}
test.cc:16: error: conversion from ‘std::vector<B, std::allocator<B> >’ to non-scalar type ‘std::vector<A, std::allocator<A> >’ requested
I would like to be able to be able to call function without having to define a new vector with elements of type A, inserting my elements of type B or changing to a vector of pointers.
No, it is not. vector<B> is not derived from vector<A>, regardless of the fact that B is derived from A. You will have to change your function somehow.
A more idiomatically C++ approach might be to template it and have it take a pair of iterators - this is why the various standard library functions (<algorithm> etc) work that way, because it separates the implementation of the algorithm from the kind of thing it's operating on.
Sometimes there are ways around this. Take a loot at Boost and some of the template meta-programming packages they have or use. Specifically I'd look at is_base_of for these kinds of purposes combined with partial template specialization.
For instance, if you wish to do some template magic trickery:
template<typename T, bool Allowed>
struct TemplateVectorCode;
You make a forward declaration of a templated class. Then you make a specialization with a "true" boolean value:
template<typename T> struct TemplateVectorCode<T, true>{
void operator(const std::vector<T>& myVector) const{ //definition in here }
};
Finally you use that with is_base_of to only instantiate instances of your template functor in the following manner:
template<typename T, typename Base>
struct MyFunction : TemplateVectorCode<T, boost::is_base_of<Base,T>::value>{
};
The important point to note is that since we have not defined a TemplateVectorCode<T, false> the compiler will throw a compile error if you attempt to use your functor with a class type T that does not derive from the type V. That means you can work with the same code in one place without having to write multiple versions of it.
(if I screwed up the partial template specialization, someone please edit it. I need to go to bed.)
Here is how to make your function accept standard vectors of any child classes of a given type (in this case, class A) using templates in C++14.
class A {};
class B : public A {};
template<typename T, std::enable_if_t<std::is_base_of_v<A, T>, bool> = true>
void function(const std::vector<T>& vec) {
// implemenation
}
std::vector<A> vec_a;
std::vector<B> vec_b;
function(vec_a); // ok
function(vec_b); // ok

Why is allocator::rebind necessary when we have template template parameters?

Every allocator class must have an interface similar to the following:
template<class T>
class allocator
{
...
template<class Other>
struct rebind { typedef allocator<Other> other; };
};
And classes that use allocators do something redundant like this:
template<class T, class Alloc = std::allocator<T> >
class vector { ... };
But why is this necessary?
In other words, couldn't they have just said:
template<class T>
class allocator { ... };
template<class T, template<class> class Alloc = std::allocator>
class vector { ... };
which is both more elegant, less redundant, and (in some similar situations) potentially safer?
Why did they go the rebind route, which also causes more redundancy (i.e. you have to say T twice)?
(Similar question goes to char_traits and the rest... although they don't all have rebind, they could still benefit from template template parameters.)
Edit:
But this won't work if you need more than 1 template parameter!
Actually, it works very well!
template<unsigned int PoolSize>
struct pool
{
template<class T>
struct allocator
{
T pool[PoolSize];
...
};
};
Now if vector was only defined this way:
template<class T, template<class> class Alloc>
class vector { ... };
Then you could just say:
typedef vector<int, pool<1>::allocator> int_vector;
And it would work perfectly well, without needing you to (redundantly) say int twice.
And a rebind operation inside vector would just become Alloc<Other> instead of Alloc::template rebind<Other>::other.
A quoted text from Foundations of Algorithms in C++11, Volume 1, chap 4, p. 35 :
template <typename T>
struct allocator
{
template <typename U>
using rebind = allocator<U>;
};
sample usage :
allocator<int>::rebind<char> x;
In The C++ Programming Language, 4th edition, section 34.4.1, p. 998, commenting the 'classical' rebind member in default allocator class :
template<typename U>
struct rebind { using other = allocator<U>;};
Bjarne Stroustrup writes this:
The curious rebind template is an archaic alias. It should have been:
template<typename U>
using other = allocator<U>;
However, allocator was defined before such aliases were supported by C++.
But why is this necessary?
What if your allocator class has more than one template argument?
That's pretty much it in terms of why it is generally discouraged to use template template arguments, in favor of using normal template arguments, even if it means a bit of redundancy at the instantiation site. In many cases (however, probably not for allocators), that argument might not always be a class template (e.g., a normal class with template member functions).
You might find it convenient (within the implementation of the container class) to use a template template parameter just because it simplifies some of the internal syntax. However, if the user has a multi-argument class template as an allocator he wants to use, but you require the user to provide an allocator which is a single-argument class template, you will in effect force him to create a wrapper for almost any new context in which he must use that allocator. This not only unscalable, it can also become very inconvenient to do. And, at this point, that solution is far from being the "elegant and less redundant" solution you originally thought it would be. Say you had an allocator with two arguments, which of the following is the easiest for the user?
std::vector<T, my_allocator<T,Arg2> > v1;
std::vector<T, my_allocator_wrapper<Arg2>::template type > v2;
You basically force the user to construct a lot of useless things (wrappers, template aliases, etc.) just to satisfy your implementation's demands. Requiring the author of a custom allocator class to supply a nested rebind template (which is just a trivial template alias) is far easier than all the contortions you require with the alternative approach.
In your approach you are forcing the allocator to be a template with a single parameter, which might not be always the case. In many cases, allocators can be non-template, and the nested rebind can return the same type of the allocator. In other cases the allocator can have extra template arguments. This second case is the case of std::allocator<> which as all templates in the standard library is allowed to have extra template arguments as long as the implementation provides default values. Also note that the existence of rebind is optional in some cases, where allocator_traits can be used to obtain the rebound type.
The standard actually mentions that the nested rebind is actually just a templated typedef:
§17.6.3.5/3
Note A: The member class template rebind in the table above is
effectively a typedef template. [ Note: In general, if the name
Allocator is bound to SomeAllocator<T>, then
Allocator::rebind<U>::other is the same type as SomeAllocator<U>,
where someAllocator<T>::value_type is T and SomeAllocator<U>::value_type is U. — end note ] If Allocator is a class template
instantiation of the form SomeAllocator<T, Args>, where Args is zero
or more type arguments, and Allocator does not supply a rebind member
template, the standard allocator_traits template uses SomeAllocator<U, Args> in place of Allocator:: rebind<U>::other by default. For
allocator types that are not template instantiations of the above
form, no default is provided.
Suppose you want to write a function taking all sorts of vectors.
Then it is much more convenient being able to write
template <class T, class A>
void f (std::vector <T, A> vec) {
// ...
}
than having to write
template <class T, template <class> class A>
void f (std::vector <T, A> vec) {
// ...
}
In most of the cases, such a function does not care about the allocator anyway.
Further note that allocators are not required to be a template. You could write separate classes for particular types that need to be allocated.
An even more convenient way of designing allocators would probably have been
struct MyAllocator {
template <class T>
class Core {
// allocator code here
};
};
Then it would have been possible to write
std::vector <int, MyAllocator> vec;
rather than the somewhat misleading expression
std::vector <int, MyAllocator<int> > vec;
I am not sure whether the above MyAllocator is permitted to be used as an allocator after adding a rebind, i.e. whether the following is a valid allocator class:
struct MyAllocator {
template <class T>
class Core {
// allocator code here
};
template <class T>
struct rebind { using other=Core<T>; };
};

Conversion from STL vector of subclass to vector of base class

I am wondering if it is possible to convert a vector of derived class values to a vector of base class values. Specifically I want to be able to pass a vector of base class objects to a function whose formal parameters takes a vector of base class. It does not appear to be possible directly as the following code example produces an error (using g++):
#include <vector>
class A {
};
class B : public A {
};
void function(std::vector<A> objs) {
}
int main(int argc, char **argv) {
std::vector<B> objs_b;
objs_b.push_back(B());
function(objs_b);
}
test.cc:16: error: conversion from ‘std::vector<B, std::allocator<B> >’ to non-scalar type ‘std::vector<A, std::allocator<A> >’ requested
I would like to be able to be able to call function without having to define a new vector with elements of type A, inserting my elements of type B or changing to a vector of pointers.
No, it is not. vector<B> is not derived from vector<A>, regardless of the fact that B is derived from A. You will have to change your function somehow.
A more idiomatically C++ approach might be to template it and have it take a pair of iterators - this is why the various standard library functions (<algorithm> etc) work that way, because it separates the implementation of the algorithm from the kind of thing it's operating on.
Sometimes there are ways around this. Take a loot at Boost and some of the template meta-programming packages they have or use. Specifically I'd look at is_base_of for these kinds of purposes combined with partial template specialization.
For instance, if you wish to do some template magic trickery:
template<typename T, bool Allowed>
struct TemplateVectorCode;
You make a forward declaration of a templated class. Then you make a specialization with a "true" boolean value:
template<typename T> struct TemplateVectorCode<T, true>{
void operator(const std::vector<T>& myVector) const{ //definition in here }
};
Finally you use that with is_base_of to only instantiate instances of your template functor in the following manner:
template<typename T, typename Base>
struct MyFunction : TemplateVectorCode<T, boost::is_base_of<Base,T>::value>{
};
The important point to note is that since we have not defined a TemplateVectorCode<T, false> the compiler will throw a compile error if you attempt to use your functor with a class type T that does not derive from the type V. That means you can work with the same code in one place without having to write multiple versions of it.
(if I screwed up the partial template specialization, someone please edit it. I need to go to bed.)
Here is how to make your function accept standard vectors of any child classes of a given type (in this case, class A) using templates in C++14.
class A {};
class B : public A {};
template<typename T, std::enable_if_t<std::is_base_of_v<A, T>, bool> = true>
void function(const std::vector<T>& vec) {
// implemenation
}
std::vector<A> vec_a;
std::vector<B> vec_b;
function(vec_a); // ok
function(vec_b); // ok

Partially defaulting template arguments using typedefs?

I am trying to do something like this:
template <typename T,bool Strong=true>
class Pointer {...};
template <typename T>
typedef Pointer<T,false> WeakPointer;
But this is a compile error ("a typedef template is illegal" VC).
I am trying to avoid doing this using inheritance, beacuse that's more unnecessary work (rewriting constructors, operator =, back-and-forth casting, friendship...).
Any ideas?
C++0x will alleviate this issue, but as it stands you cannot.
The common work-around is this:
template <typename T,bool Strong=true>
class Pointer {...};
template <typename T>
struct WeakPointer
{
typedef Pointer<T,false> value_type;
};
So instead of:
typedef WeakPointer<int> WeakInt;
You get:
typedef WeakPointer<int>::value_type WeakInt;
C++03 doesn't support templated typedefs. You'd have to specify both types:
typedef Pointer<int,false> WeakIntPointer;
I know that isn't very helpful, but it's a reality of the language. Luckily, C++0x will support template typedefs.
For now, you'd really have to make a templated WeakPointer class which takes a template parameter to indicate the type.

Template Partial Specialization - any real-world example?

I am pondering about partial specialization. While I understand the idea, I haven't seen any real-world usage of this technique. Full specialization is used in many places in STL so I don't have a problem with that. Could you educate me about a real-world example where partial specialization is used? If the example is in STL that would be superior!
C++0x comes with unique_ptr which is a replacement for auto_ptr which is going to be deprecated.
If you use unique_ptr with an array type, it uses delete[] to free it, and to provide operator[] etc. If you use it with a non-array type, it uses delete. This needs partial template specialization like
template<typename T>
struct my_unique_ptr { ... };
template<typename T>
struct my_unique_ptr<T[]> { ... };
Another use (although a very questionable) is std::vector<bool, Allocator> in the standard library. The bool specialization uses a space optimization to pack bools into individual bits
template<typename T, typename Allocator = std::allocator<T> >
struct vector { ... };
template<typename Allocator>
struct vector<bool, Allocator> { ... };
Yet another use is with std::iterator_traits<T>. Iterators are required to define the nested typedefs value_type, reference and others to the correct types (for a const iterator, reference would usually be T const&, for example) so algorithms may use them for their work. The primary template uses type-members of the iterator type in turn
template<typename T>
struct iterator_traits {
typedef typename T::value_type value_type;
...
};
For pointers, that of course doesn't work. There is a partial specialization for them
template<typename T>
struct iterator_traits<T*> {
typedef T value_type;
...
};
In some stl implementations collections like std::vector and std::list use partial template specialization to reduce the amount of code generated for collections of pointers.
Each instantiation of a template for a type T creates new code. However pointer types are effectively all the same so generating new code for every type is a waste. This can be reduced by implementing the private part of pointer collections with void pointers and then casting these to the appropriate type in the public interface. This greatly reduces the code generated for pointer collections.
I think this is covered in Effective STL.
Taken from MSDN (Partial Specialization of Class Templates (C++))
// partial_specialization_of_class_templates.cpp
template <class T> struct PTS {
enum {
IsPointer = 0,
IsPointerToDataMember = 0
};
};
template <class T> struct PTS<T*> {
enum {
IsPointer = 1,
IsPointerToDataMember = 0
};
};
template <class T, class U> struct PTS<T U::*> {
enum {
IsPointer = 0,
IsPointerToDataMember = 1
};
};