Template class with iterator to a STL container - c++

I want to create a template class which has an iterator of a STL container as a member. That is how far I got:
#include <iostream>
#include <vector>
using namespace std;
template<typename Element, template <class> class StdLibContainer>
struct ClassHoldingAnIteratorToAStandardContainer
{
ClassHoldingAnIteratorToAStandardContainer(){}
typename StdLibContainer<Element*>::iterator std_lib_iterator;
};
int main()
{
vector<int> vec{1,2,3};
ClassHoldingAnIteratorToAStandardContainer<int,vector<int>> holding_iterator_to_vec;
//DOES NOT WORK, compiler says: expected a class template, got ‘std::vector<int>’
return 0;
}
Could you explain the syntax template <typename> class StdLibContainer?
I found it somewhere on stackoverflow. BUt I don't understand it.
How can I create an instance of ClassHoldingAnIteratorToAStandardContainer ? All my attempts failed so far. The compiler always gives the error message: `expected a class template, got ‘std::vector’
In the above example i want to assign holding_iterator_to_vec vec.begin().

template <typename> class is the same as template <class> class. Originally, when templates were introduced, they allowed two equivalent forms:
template<class T> struct Foo {};
// or
template<typename T> struct Foo {};
Do not ask me why! However, the same was not true for template template parameters:
template <template <class> typename T> struct Foo {};
was the only allowed syntax. Apparently, people were unhappy about it, so the syntax was relaxed.
As for your second question, std::vector takes at least two template arguments, data type and allocator. This is why a single argument template doesn't cut it before C++17. After C++17, it would work.
To make it universal, use
template<template <class...> class Container> struct Foo{};

Unless you really need to know the type of the container, I would strongly recommend to keep your ClassHoldingAnIteratorToAStandardContainer independent of the concrete container type. If you just need the iterator, this is simpler and sufficient:
template<typename iterator>
struct iterator_wrapper {
iterator iter;
};
Thats the minimum you need to have an iterator as member :).
I dont really know what you want to use the iterator for, so just for the sake of an example lets add methods that actually use the iterator....
#include <iterator>
#include <vector>
#include <iostream>
template<typename iterator>
struct iterator_wrapper {
using value_type = typename std::iterator_traits<iterator>::value_type;
iterator iter;
bool operator!=(const iterator& other) { return iter != other;}
iterator_wrapper& operator++(){
++iter;
return *this;
}
const value_type& operator*() { return *iter; }
};
template <typename iterator>
iterator_wrapper<iterator> wrap_iterator(iterator it) {
return {it};
}
int main() {
std::vector<int> vec{1,2,3};
auto it = wrap_iterator(vec.begin());
for (;it != vec.end();++it) std::cout << *it;
}
Also there is a problem in your code.
typename StdLibContainer<Element*>::iterator
is for containers of pointers while in main you have ints. If you want to infer the iterator type from the container type then you can do it for example like this:
template <typename container,
typename iterator = typename container::iterator>
iterator_wrapper<iterator> wrap_begin(container& c) {
return {c.begin()};
}
which makes creating an iterator_wrapper as simple as
auto x = wrap_begin(vec);
Note that this answer applies to C++11, in newer standards there are deduction guides that make such make_x methods more or less superfluous afaik.

Related

A recursive template type for a container / typename forwarding

Is there any way to get a recursive template type? I have a container for which I want to specify an underlying storage strategy. The inner template must however use the outer template's type, so it causes a loop in the type definition -- which isn't possible to specify.
About what I want:
template<typename C>
struct inner {
C * object[16];
};
template<typename T, typename Inner>
struct container {
T value;
Inner<container> holder;
};
C++11 solutions are fine (though I'm still on gcc 4.6.3).
You need to tell the compiler that Inner is a templated class:
template<typename T, template<typename> class Inner>
struct container {
T value;
Inner<container> holder;
};
I'm not sure why you're adding the Inner type template parameter, since you're defining holder to be a type based on Container and inner, both of which are available at the point you're declaring holder.
Are you planning on using any type other than struct inner as a template param to Container? If not, the following simplified code compiled and ran for me in VS2010 :
#include <vector>
#include <stdio.h>
template <typename C>
struct inner{
C * objects[16];
bool hasobj;
inner():hasobj(false){}
};
template <typename T>
class Container {
inner<Container> holder;
T value;
public:
Container(const T& valueP){
value = valueP;
}
void AddChild(Container* rhs){
holder.objects[0] = rhs; //Always using first location, just for example
holder.hasobj = true;
}
void PrintStuff()const{
if(holder.hasobj){
holder.objects[0]->PrintStuff();
}
printf("VAL IS %d\n", value);
}
};
int main(){
Container<int> c(10);
Container<int> c1(20);
c1.AddChild(&c);
c1.PrintStuff();
}
Basically, this is assuming that the container is always defining holder in terms of inner, which helps get rid of the extra template parameter, when defining Container. Hope this helps :)
arun

How to check whether a container is stable

std::vector is an unstable container, i.e. by resizing the vector, iterators might become invalidated.
In contrast, std::list or boost::container::stable_vector are stable containers which keep the iterators valid until the removal of the corresponding element.
Is there a way to check whether a given container is stable? For instance, if I have something like
template<template <typename A, typename B=std::allocator<A> > class T=std::list>
class Foo
{
}
Is it possible to allow only for stable containers and forbid the unstable ones?
I don't think there is anything available providing such information, but you could write your own trait. However, you will need to specialize it for every stable container that may be used, which is perhaps not an option.
#include <boost/container/vector.hpp>
#include <iostream>
#include <type_traits>
#include <list>
#include <vector>
template <template <typename...> class Container>
struct is_stable
: std::false_type
{};
template <>
struct is_stable<std::list>
: std::true_type
{};
template <>
struct is_stable<boost::container::stable_vector>
: std::true_type
{};
template<template <typename...> class Container = std::list>
class Foo
{
static_assert(is_stable<Container>::value, "Container must be stable");
};
int main()
{
Foo<std::list> f1; // ok
Foo<std::vector> f2; // compiler error
}
I don't think there is a way you can automatically detect that a container is stable, without resorting to manual specialization.
Just for fun, I tried writing what the concept/axiom for stability would look like (concepts and axioms are an extension to the language that were considered for inclusion in C++11):
concept StableGroup<typename C, typename Op>
: Container<C>
{
void operator()(Op, C, C::value_type);
axiom Stability(C c, Op op, C::size_type index, C::value_type val)
{
if (index <= c.size())
{
auto it = std::advance(c.begin(), index);
op(c, val);
return it;
}
<->
if (index <= c.size())
{
op(c, val);
return std::advance(c.begin(), index);
}
}
}
If think this correctly captures the requirement that every iterator over the original container is equivalent to the corresponding iterator over the modified container. Not sure this is very useful, but coming up with such axioms is an interesting exercise :)!

Copying from std container frm arbitrary source object

I created a read only iterator which allows me to use it in a for loop more conveniently then with the std iterators, similar to what boost does with the FOREACH (not as good but good enough :))
Now it looks like this:
for(ReadOnylIterator<MyClass *> class = parent.getIterator(); class.end(); ++class)
class->function();
The problem that I have now is, that I must implement a function on the parent which returns the iterator. Since the std containers have all the same syntax, I was wondering if it is possible to define a copy constructor/assignment operator on the Iterator that accepts any of the std:: containers and creates the copy itself, instead of requiring the class to return it.
Of course I want to avoid having to define all of them myself like as there are lots of them:
ReadOnlyIterator<T> &operator=(std::list<T> const &v)
ReadOnlyIterator<T> &operator=(std::vector<T> const &v)
...
Is there a way to do this? When I look at the source of the vector I don't see a common base class, so I think it might not be posssible.
I don't understnad why the assignment operator doesn't work.
In my code I test it like this:
std::vector<SimpleClass *>t;
ReadOnlyIterator<SimpleClass *> &it = t;
And I get
error C2440: 'initializing' : cannot convert from 'std::vector<_Ty>' to 'ReadOnlyIterator<T> &'
If I understand you correctly, this should work:
#include <type_traits>
template <typename Container>
typename std::enable_if<std::is_same<T, typename Container::value_type>::value, ReadOnlyIterator<T>&>::type operator= (const Container &v);
The above code uses C++11. If you don't have access to that, you could use the equivalent functionality from Boost.
Live example
In case you can use neither C++11 nor Boost, you can code the necessary classes yourself:
template <typename T, typename U>
struct is_same
{
enum { value = 0 };
};
template <typename T>
struct is_same<T, T>
{
enum { value = 1 };
};
template <bool, typename>
struct enable_if
{};
template <typename T>
struct enable_if<true, T>
{
typedef T type;
};
To use this in a constructor, define it like this:
template <typename Container>
ReadOnlyIterator(const Container &v, typename enable_if<is_same<T, typename Container::value_type>::value, void>::type * = 0) {}
Live example
I'm sorry but no, this is not possible given that the containers don't have common base classes. You'll have to write an operator for each container, Sad news !
Although if the behavior of the operator functions is always the same, you could just make a macro that contains the code, and copy paste it for every container type ^_^

Templates and STL

The following code represents a container based on std::vector
template <typename Item>
struct TList
{
typedef std::vector <Item> Type;
};
template <typename Item>
class List
{
private
typename TList <Item>::Type items;
....
}
int main()
{
List <Object> list;
}
Is it possible to templatize std::vector and create a general container, something like that?
template <typename Item, typename stl_container>
struct TList
{
typedef stl_container<Item>;
};
where stl_container represents std::vector, std::list, std::set...? I would like to choose the type of container at the time of the creation.
List <Object, std::vector> list; //vector of objects, not a real code
List <Object, std::vector> list; //list of objects, not a real code
Thanks for your answers...
Updated question:
I tried the following code but there are errors:
#include <vector>
template <typename Item, typename Container>
struct TList
{
typedef typename Container <Item>::type type; //Error C2059: syntax error : '<', Error C2238: unexpected token(s) preceding ';
};
template <typename T>
struct vector_container
{
typedef std::vector<T> type;
};
int _tmain(int argc, _TCHAR* argv[])
{
TList <int, vector_container> v;
TList <int, map_container> m;
}
Yes, but not directly:
template <typename Item, template <typename> class Container>
struct TList
{
typedef typename Container<Item>::type type;
};
Then you can define different container policies:
template <typename T>
struct vector_container
{
typedef std::vector<T> type;
};
template <typename T>
struct map_container
{
typedef std::map<T, std::string> type;
};
TList<int, vector_container> v;
TList<int, map_container> m;
A bit verbose, though.* To do things directly, you'd need to take the route described by James, but as he notes this is ultimately very inflexible.
However, with C++0x we can do this just fine:
#include <map>
#include <vector>
template <typename Item,
template <typename...> class Container, typename... Args>
struct TList
{
// Args lets the user specify additional explicit template arguments
Container<Item, Args...> storage;
};
int main()
{
TList<int, std::vector> v;
TList<int, std::map, float> m;
}
Perfect. Unfortunately there's no way to reproduce this in C++03, except via the indirection policy classes introduce as described above.
*I want to emphasize that by "A bit verbose" I mean "this is unorthodox". The correct solution for your problem is what the standard library does, as Jerry explains. You just let the user of your container adapter specify the entire container type directly:
template <typename Item, typename Container = std::vector<Item>>
struct TList
{};
But this leaves a big problem: what if I don't want the value type of the container to be Item but something_else<Item>? In other words, how can I change the value type of an existing container to something else? In your case you don't, so read no further, but in the case we do, we want to rebind a container.
Unfortunately for us, the containers don't have this functionality, though allocators do:
template <typename T>
struct allocator
{
template <typename U>
struct rebind
{
typedef allocator<U> type;
};
// ...
};
This allows us to get an allocator<U> given an allocator<T>. How can we do the same for containers without this intrusive utility? In C++0x, it's easy:
template <typename T, typename Container>
struct rebind; // not defined
template <typename T, typename Container, typename... Args>
struct rebind<T, Container<Args...>>
{
// assumes the rest are filled with defaults**
typedef Container<T> type;
};
Given std::vector<int>, we can perform rebind<float, std::vector<int>>::type, for example. Unlike the previous C++0x solution, this one can be emulated in C++03 with macros and iteration..
**Note this mechanism can be made much more powerful, like specifying which arguments to keep, which to rebind, which to rebind themselves before using as arguments, etc., but that's left as an exercise for the reader. :)
I'm a bit puzzled why some very smart (and competent) people are saying no.
Unless I've misread your question, what you're trying to accomplish is virtually identical to the "container adapters" in the standard library. Each provides an interface to some underlying container type, with the container type that will be used provided as a template parameter (with a default value).
For example, a std::stack uses some other container (e.g., std::deque, std::list or std::vector) to hold the objects, and std::stack itself just provides a simplified/restricted interface for when you just want to use stack operations. The underlying container that will be used by the std::stack is provided as a template parameter. Here's how the code looks in the standard:
namespace std {
template <class T, class Container = deque<T> >
class stack {
public:
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef Container container_type;
protected:
Container c;
public:
explicit stack(const Container& = Container());
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
value_type& top() { return c.back(); }
const value_type& top() const { return c.back(); }
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_back(); }
};
}
Of course, perhaps I've just misunderstood the question -- if so, I apologize in advance to the people with whom I'm (sort of) disagreeing.
Yes and no.
You can use a template template parameter, e.g.,
template <typename Item, template <typename> class Container>
struct TList { /* ... */ };
However, in general, template template parameters are not particularly useful because the number and types of the template parameters have to match. So, the above would not match std::vector because it actually has two template parameters: one for the value type and one for the allocator. A template template parameter can't take advantage of any default template arguments.
To be able to use the std::vector template as an argument, TList would have to be declared as:
template <typename Item, template <typename, typename> class Container>
struct TList { /* ... */ };
However, with this template, you wouldn't be able to use the std::map template as an argument because it has four template parameters: the key and value types, the allocator type, and the comparator type.
Usually it is much easier to avoid template template parameters because of this inflexibility.
well, you can hack it up with a macro:
template <typename T, typename stl_container = std::vector<T> >
struct TList
{
typedef stl_container Type;
};
#define TLIST(T, C) TList<T, C<T> >
TList<int> foo;
TList<int, std::list<int> > bar;
TLIST(int, std::list) baz;
Is it possible to templatize std::vector and create a general container, something like that?
No. You would have to templatize the function or object using the container -- you couldn't templatize the container itself.
For example. consider a typical std::find:
template<class InputIterator, class T>
InputIterator find ( InputIterator first, InputIterator last, const T& value )
{
for ( ;first!=last; first++) if ( *first==value ) break;
return first;
}
This works for any container, but doesn't need a tempalte with the container at all.
Also, given that it looks what you're trying to do is make container independent code, you might want to buy or borrow yourself a copy of Scott Meyers' Effective STL and read Item 2: Beware the illusion of container-independent code.
You can use template template parameters as others have mentioned here. The main difficulty with this is not that dissimilar container types have dissimilar template parameters, but that the standard allows the standard containers, like vector, to have template parameters in addition to the documented, necessary ones.
You can get around this by providing your own subclass types that accept the appropriate template parameters and let any extras (which have to have defaults) be filled in my the implementation:
template < typename T > struct simple_vector : std::vector<T> {};
Or you can use the templated typedef idiom:
template < typename T > struct retrieve_vector { typedef std::vector<T> type; };

simple C++ templates suited for STL Containers

I need a template like this, which work perfectly
template <typename container> void mySuperTempalte (const container myCont)
{
//do something here
}
then i want to specialize the above template for std::string so i came up with
template <typename container> void mySuperTempalte (const container<std::string> myCont)
{
//check type of container
//do something here
}
which doesnt't work, and throws an error. I would like to make the second example work and then IF possible i would like to add some code in the template to check if a std::vector/std::deque/std::list was used, to do something differently in each case.
So i used templates because 99% of the code is the same for both vectors and deques etc.
To specialize:
template<> void mySuperTempalte<std:string>(const std::string myCont)
{
//check type of container
//do something here
}
To specialize for vector:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
To specialize for deque:
template<typename C> void mySuperTempalte (std::deque<C> myCont)
{
//check type of container
//do something here
}
Have you tried a template typename parameter? The syntax is a bit weird because it emulates the syntax used to declare such a container. There's a good InformIT article explaining this in more detail.
template <template <typename> class Container>
void mySuperTemplate(Container<std::string> const& cont) {
}
Notice that you also should declare the argument as a reference!
By the way: this comment
//check type of container
is a dead giveaway that you're doing something wrong. You do not want to check the type of the container. User more sophisticated overloading instead, as shown in sep's answer.
If I am understanding your problem correctly you have an algorithm that will work for STL containers vector, deque etc but are trying to write a template specialisation for string. If this is the case then you can write the generalised templated method that you defined in your question:-
template<typename container> void mySuperTempalte( const container &myCont )
{
// Implement STL container code
}
Then for your string specialisation you declare:-
template<> void mySuperTempalte( const container<std::string> &myCont )
{
// Implement the string code
}
For any other specialisation just change the type declaration for myCont. If you really need to do this for the vector and deque containers then make the template parameter the parameter for the type in that container rather than the container itself as Sep suggested.
template<typename C> void mySuperTempalte( const std::vector<C> &myCont)
{
// check type of container
// do something here
}
It's worth trying to avoid this by making your first implementation work with all STL containers to make your life easier, then you only need the specialisation for the string class. Even consider converting your string to a vector to avoid the specialisation all together.
On a side note, I've changed the container parameter to a const reference, I assume this is what you want, as you declare the object const anyway, this way you avoid a copy.
The answers so far seem helpful, but I think I'd use a different construct. I expect all containers to define value_type, just like the STL containers do. Therefore, I can write
inline template <typename C> void mySuperTemplate (C const& myCont)
{
mySuperTemplateImpl<C, typename C::value_type>(myCont);
}
In general, it's easier to act on a parameter that you've extracted explicitly.
#sep
'Simple' solution
The answer posted by 'sep' is pretty good, probably good enough for 99% of app developers, but could use some improvement if it's part of a library interface, to repeat:
To specialize for vector:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
This will work provided the caller isn't using std::vector. If this works well enough for you, to specialize for vector, list, etc, then stop here and just use that.
More complete solution
First, note that you can't partially specialize function templates -- you can create overloads. And if two or more of them match to the same degree, you will get "ambigous overload" errors. So we need to make exactly one match in every case you want to support.
One technique for doing this is using the enable_if technique -- enable_if allows you to selectively take function template overloads out of the possible match list using an obscure language rule... basically, if some boolean expression is false, the overload becomes 'invisible'. Look up SFINAE for more info if you're curious.
Example. This code can be compiled from the command line with MinGW (g++ parameterize.cpp) or VC9 (cl /EHsc parameterize.cpp) without error:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <bool B, class T> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };
template <class T, class U> struct is_same { enum { value = false }; };
template <class T> struct is_same<T,T> { enum { value = true }; };
namespace detail{
// our special function, not for strings
// use ... to make it the least-prefered overload
template <class Container>
void SpecialFunction_(const Container& c, ...){
cout << "invoked SpecialFunction() default\n";
}
// our special function, first overload:
template <class Container>
// enable only if it is a container of mutable strings
typename enable_if<
is_same<typename Container::value_type, string>::value,
void
>::type
SpecialFunction_(const Container& c, void*){
cout << "invoked SpecialFunction() for strings\n";
}
}
// wrapper function
template <class Container>
void SpecialFunction(const Container& c){
detail::SpecialFunction_(c, 0);
}
int main(){
vector<int> vi;
cout << "calling with vector<int>\n";
SpecialFunction(vi);
vector<string> vs;
cout << "\ncalling with vector<string>\n";
SpecialFunction(vs);
}
Output:
d:\scratch>parameterize.exe calling
with vector<int> invoked
SpecialFunction() default
calling with vector<string> invoked
SpecialFunction() for strings
d:\scratch>
Whether it is a good design or not is left for further discussion. Anyway, you can detect the type of container using partial template specializations. In particular:
enum container_types
{
unknown,
list_container,
vector_container
};
template <typename T>
struct detect_container_
{
enum { type = unknown };
};
template <typename V>
struct detect_container_< std::vector<V> > // specialization
{
enum { type = vector_container };
};
template <typename V>
struct detect_container_< std::list<V> >
{
enum { type = list_container };
};
// Helper function to ease usage
template <typename T>
container_types detect_container( T const & )
{
return static_cast<container_types>( detect_container_<T>::type );
}
int main()
{
std::vector<int> v;
assert( detect_container( v ) == vector_container );
}