I am writing a little template class which can get as template parameter list or vector (and the data type obviously).
I need to overload [ ] operator, to do this I want to use the overloaded [ ] of the vector and make a simple search (next, next, until we get to the desired index) for the list.
So I am checking with typeid if parameter is parameter of list and implements according to result like this:
const T* operator[](size_t _index)const
{
if(typeid(ContainerT<T,std::allocator<T> >) == typeid(vector<T>))
{
return m_container[_index];
}
else
{
const_iterator it = m_container.begin();
for(int i=0;i<_index;++i)
{
++it;
}
return *it;
}
}
If I dont use the [ ] for the list, everything is ok, but as I use it:
tContainer_t<int, list> list1;
cout<<list1[0]<<endl;
it is not compiling at all and here is the compilation error:
In file included from main.cpp:6:0:
tContainer.h: In member function ‘const T* tContainer_t<T, ContainerT>::operator[](size_t) const [with T = int, ContainerT = std::list, size_t = unsigned int]’:
main.cpp:68:9: instantiated from here
tContainer.h:80:29: error: no match for ‘operator[]’ in ‘((const tContainer_t<int, std::list>*)this)->tContainer_t<int, std::list>::m_container[_index]’
I dont understand since I checked that the typeid does work (well I think...) and anyway it seems the compiler sees that subscript will also be called for list.
Since the compiler needs to compile the entire function, even though one branch will not be taken at runtime (due to check), then you can't use this type of runtime checking to prevent the compilation error.
There are ways to do this involving using a helper function that can be specialized for the type. However, it can be complicated and in this case, not worth doing yourself, as the standard library has already done the work for you.
std::advance (located in header <iterator>) can be used to advance an iterator up to N times and is optimized for random-access iterators (like those returned by std::vector or std::deque) to do it in constant-time. Otherwise it falls back to steping one at a time using ++
// Note, changed signature to return const T&, which is more standard for operator[]
const T& operator[](size_t index) const
{
const_iterator itr = m_container.begin();
std::advance(itr, index);
return *itr;
}
Edit:
Assuming you wanted to learn how it's done, you would create the following functions, usually in a separate namespace. For now, I'm going to use the original intent of the question, and assume that you're using std::list or std::vector.
namespace helper
{
template <typename T, typename Alloc>
typename std::vector<T,Alloc>::const_reference
index_into(std::vector<T, Alloc> const& container, std::size_t index)
{
return container[index];
}
template <typename T, typename Alloc>
typename std::list<T,Alloc>::const_reference
index_into(std::list<T, Alloc> const& container, std::size_t index)
{
std::list<T, Alloc>::const_iterator itr = container.begin();
for(std::size_t i = 0; i < index; ++i)
{
++itr;
}
return *itr;
}
}
// Change your definition here
const T& operator[](size_t index) const
{
return helper::index_into(m_container, index);
}
Why this works: When you compile this with either std::list or std::vector, it uses function overloading to determine which of the two overloads of index_into to use. Hence, it only compiles the one that is legal, and doesn't attempt to compile both.
Note this, implementation only allows std::vector and std::list. If you wanted to allow any container, using std::advance is the generic and correct solution.
FYI, the implementation of std::advaance uses a similar technique. You can look at your implementation to see how it's done.
Use std::advance from <iterator>:
const T* operator[](size_t index) const
{
const_iterator it = m_container.begin();
std::advance(it, index);
return &*it;
}
Related
Which C++20 standard library containers have a .at function? For example, at least std::map, std::unordered_map and std::vector do. What others are there?
Is there some way to work this out without going through the 2000 page standard by hand?
From comments, it seems you want something like:
template <typename Container, typename T>
typename Container::pointer my_at(Container&, const T&)
requires (requires(Container c, const T& key) { c.at(key); })
{
// ...
}
Demo
I don't think a pointer is the appropriate type to return for this operation, instead it should be an iterator. At which point the definition splits into two cases:
Random access containers:
iterator at_(size_type index) noexcept { return index < size() ? begin() + index : end(); }
const_iterator at_(size_type index) const noexcept { return index < size() ? begin() + index : end(); }
map and unordered_map:
template<typename T>
iterator at_(T && key) noexcept { return find(std::forward<T>(key)); }
template<typename T>
const_iterator at_(T && key) const noexcept { return find(std::forward<T>(key)); }
And then rather than testing against nullptr, you test against the container's end().
It's also a reasonable question as to whether (unordered_)map needs an alias for an existing member to match your nomenclature
I ended up grepping libstdc++ include directory for \bat( and that has given me:
std::basic_string
std::basic_string_view
std::array
std::vector
std::vector<bool>
std::unordered_map
std::map
std::dequeue
I'm not sure if this is exhaustive.
There is also rope and vstring but I don't think these are standard.
I'm trying to create my own data-structure that can determine if a value is an element within it in O(1) time with a hash-map.
I'm working on adding more member functions so that it's more similar to the STL containers. Here's what I currently have that's relevant to the problem:
template <class T>
class setfind {
private:
long long _size = 0;
unordered_map<T, bool> _set;
public:
// constructors
setfind() {}
// initialize from some iterable
template <class InputIterator>
setfind(InputIterator beg, InputIterator en){
_size = en - beg;
while (beg != en){
_set[*beg] = true;
beg++;
}
}
bool contains(const T &val){
return _set[val];
}
bool contains(const T &&val){
return _set[val];
}
};
As you can see, its core is the unordered_map. I want to write a member function that returns a begin iterator to the _set variable. I tried putting this in:
template <class InputIterator>
InputIterator begin()
{
return _set.begin();
}
but that led to a compilation error saying that there was no matching member function.
I don't know enough about iterators and template-classes to fix this. Does anyone know how to implement it or what's wrong? Are there any good resources so that I can learn more about this?
Also some optimization tips for this class would be appreciated because this is going to be used under a time-limit.
EDIT: I’m restricted to using c++11
EDIT2: Fixed a bug in the constructor
EDIT3: Memory leaks and best-practices will not be an issue
I see several issues with your code.
You don't need the _size member at all, get rid of it and use _set.size() when needed.
In your constructor, while (*beg != *en) needs to be while (beg != en) instead. Or better, just geet rid of the manual loop altogether and use the std::unordered_map constructor that takes an iterator pair as input:
// initialize from some iterable
template <class InputIterator>
setfind(InputIterator beg, InputIterator en) : _set(beg, en) {}
In your contains() methods, use _set.find() or _set.contains() instead of _set.operator[] to avoid val begin added to the _set if it does not already exist. Also, it does not make sense to take a const rvalue reference, so just get rid of that overload altogether:
bool contains(const T &val) const
{
return _set.find(val) != _set.end();
// or:
// return _set.contains(val);
}
And lastly, for your begin() method, just use auto for the return type instead of a template, let the compiler deduce the necessary type, eg:
auto begin()
{
return _set.begin();
}
UPDATE: apparent auto return type deduction was introduced in C++14. So, for C++11, you will just have to state the type explicitly, still don't use a template for it, eg:
unordered_map<T, bool>::iterator begin()
{
return _set.begin();
}
Or:
auto begin() -> unordered_map<T, bool>::iterator
{
return _set.begin();
}
Or:
auto begin() -> decltype(_set.begin())
{
return _set.begin();
}
You can simplify this by declaring an iterator alias in your class (which you should do anyway, if your goal is to make your class act like a standard container), eg:
template <class T>
class setfind {
private:
unordered_map<T, bool> _set;
public:
using iterator = unordered_map<T, bool>::iterator;
...
iterator begin(){
return _set.begin();
}
};
I'm currently using a third-party library which contains a class that only provides indexed lookup, i.e. operator[].
I'd like to do a range-based for loop on this class's contents. However, having never written an iterator or iterator adapter, I'm quite lost. It seems that writing iterators is not a straightforward task.
My desired usage is:
for(auto element : container)
{
...
}
Instead of having to write:
for(int i = 0; i < container.size(); ++i)
{
auto element = container[i];
...
}
How can this be achieved? Does Boost provide this functionality?
Writing iterators is actually a rather straightforward task, but it gets extremely tedious. Since your container supports indexing by an integer, I assume its iterators would fall into the random access iterator category (if they existed). That needs a lot of boilerplate!
However, to support the range-based for loop, all you'll need is a forward iterator. We'll write a simple wrapper for the container that implements the forward iterator requirements, and then write two functions Iterator begin(Container&) and Iterator end(Container&) that enable the container to be used in the range-based for loop.
This Iterator will contain a reference to the container, the size of the container, and the current index within that container:
template<template<typename> class C, typename T>
class indexer : public std::iterator<std::forward_iterator, T>
{
public:
indexer(C<T>& c, std::size_t i, std::size_t end)
: c_(std::addressof(c)), i_(i), end_(end) {}
T& operator*() const {
return c_[i_];
}
indexer<C, T>& operator++() {
++i_;
return *this;
}
indexer<C, T> operator++(int) {
auto&& tmp = *this;
operator++();
return tmp;
}
bool operator==(indexer<C, T> const& other) const {
return i_ == other.i_;
}
bool operator!=(indexer<C, T> const& other) const {
return !(*this == other);
}
private:
C<T>* c_;
std::size_t i_, end_;
};
Inheriting from std::iterator conveniently declares the appropriate typedefs for use with std::iterator_traits.
Then, you would define begin and end as follows:
template<typename T>
indexer<Container, T> begin(Container<T>& c) {
return indexer<Container, T>(c, 0, c.size());
}
template<typename T>
indexer<Container, T> end(Container<T>& c) {
auto size = c.size();
return indexer<Container, T>(c, size, size);
}
Switch out Container for whatever the type of container is in your example, and with that, your desired usage works!
The requirements and behavior of all the various kinds of iterators can be found in the tables of section 24.2.2 of the standard, which are mirrored at cppreference.com here.
A random-access iterator implementation of the above, along with a demo of usage with a simple vector_view class can be found live on Coliru or ideone.com.
You can do the following:
1) define your own iterator It that contains, inside, a ref ref to your container container and an index i. When the iterator is dereferenced, it returns ref[i] by reference. You can write it yourself or you can use boost for help, it has an iterator library to easily define your own iterators. Constructor should accept a container& and a size_t. You can make also the const_iterator if this concept applies.
2) When operator++ is invoked on one iterator, it simply does ++i on the internal member. operator== and operator!= should simply compare i. You can assert, for security, that both iterators are coherent, that means their refs point to the same object.
3) add begin and end to your container class or, if this is not possible, define a global begin and end that accept your container& c. begin should simply return It(c, 0). end should return It(c, c.size()).
There could be a problem copying the iterators as they contain a reference and some other minor details, but I hope the overall idea is clear and correct.
I'd like to have a function as described in title.
I've noticed that STL algorithms that work with containers of any type (list, vector, etc) containing elements of any type (int, double) provide genericity by using iterator types as template parameters, e.g.
template<typename _II, typename _OI>
inline _OI
copy(_II __first, _II __last, _OI __result)
This is a good method until the algorithm works for any type of elements. The only requirement for element type is that it must have copy constructor.
But suppose we have one concrete type
class MyElement
{
public:
void doSomethingWithElement();
};
and we want to implement a function that processes number of elements of this type by calling function doSomethingWithElement().
Writing a function that receives container of specific type is not very convenient because many containers are treated in the same way (e.g. iterators), and if there will be need for processing containers of different types we'll be forced to duplicate the code. Writing a template works fine, but it seems ugly because we have to implement function in place where it is declared (in header file). Also, when we want to process elements of only one type, parametrizing this type is not the right way to achieve the goal.
I've been thinking about iterator interface that could be used like
void processContainer(IIterator<MyElement> begin, IIterator<MyElement> end);
If this iterator had pure virtual operator++ and operator* that were implemented in derived classes, we could pass such objects to processContainer. But there is a problem: if IIterator is abstract class, we can't instantiate it in the implementation of processContainer, and if we pass a pointer to IIterator, this function will be able to modify it.
Does anybody know any other hack to do this? Or would be another approach better than these ones above? Thanks in advance.
The simpler approach is to ignore the restriction and just implement your function as a template for any iterator. If the iterator does not refer to the type, then the user will get a horrible error message in the lines of "type X does not have doSomethingWithElement member function`.
The next thing would be to provide a static_assert, the function would still take any iterator (meaning that it will participate in overload resolution for any type) but the error message will be slightly more informative.
Furthermore you can decide to use SFINAE to remove the overload from the set of candidates. But while SFINAE is a beautiful golden hammer, I am not sure that you have the appropriate nail at hand.
If you really want to go further down the lane, you can take a look at any_iterator in the Adobe libraries as an example on how to perform type erasure on the iterator type to avoid the template. The complexity of this approach is orders of magnitude higher than any of the previous, and the runtime cost will also be higher, providing the only advantage of a cleaner ABI and less code size (different iterators can be passed to a single function).
You could use std::for_each(): http://www.cplusplus.com/reference/algorithm/for_each/
full code:
void callDoSomething(MyElement &elem)
{
elem.doSomething();
}
int main()
{
std::vector<MyElement> vec(100);
std::for_each(vec.begin(), vec.end(), callDoSomething);
}
You can't do exactly what you want to do. You could use enable_if to limit the function's availability:
template < typename Container >
typename enable_if<is_same<typename Container::value_type, MyElement>,void>::type processContainer(Container c)...
It's not possible to create an abstract iterator that has the full iterator functionality - including the ability to make copies of itself - without changing the iterator interface. However, you can implement a subset of iterator functionality using an abstract base class:
#include <iterator>
#include <vector>
#include <list>
template<typename T>
struct AbstractIterator
{
virtual bool operator!=(const AbstractIterator<T>& other) const = 0;
virtual void operator++() = 0;
virtual T& operator*() = 0;
};
template<typename Iterator>
struct ConcreteIterator : AbstractIterator<typename std::iterator_traits<Iterator>::value_type>
{
typedef typename std::iterator_traits<Iterator>::value_type value_type;
Iterator i;
ConcreteIterator(Iterator i) : i(i)
{
}
virtual bool operator!=(const AbstractIterator<value_type>& other) const
{
return i != static_cast<const ConcreteIterator*>(&other)->i;
}
virtual void operator++()
{
++i;
}
virtual value_type& operator*()
{
return *i;
}
};
template<typename Iterator>
ConcreteIterator<Iterator> wrapIterator(Iterator i)
{
return ConcreteIterator<Iterator>(i);
}
class MyElement
{
public:
void doSomethingWithElement();
};
void processContainerImpl(AbstractIterator<MyElement>& first, AbstractIterator<MyElement>& last)
{
for(; first != last; ++first)
{
(*first).doSomethingWithElement();
}
}
template<typename Iterator>
void processContainer(Iterator first, Iterator last)
{
ConcreteIterator<Iterator> wrapFirst = wrapIterator(first);
ConcreteIterator<Iterator> wrapLast = wrapIterator(last);
return processContainerImpl(wrapFirst, wrapLast);
}
int main()
{
std::vector<MyElement> v;
processContainer(v.begin(), v.end());
std::list<MyElement> l;
processContainer(l.begin(), l.end());
}
I have a template class template<typename T, typename R>. R is of type vector<T*> or list<T*>.
I want my class to overload [] operator so that in case it is a vector I will use the built in [] operator for efficiency and in case it's a list I will implement it with iterator.
To me it sounds like a job for template specialization so I thought to write something like this:
template<typename T, typename R>
T& tContainer_t<T, R>::operator[]( unsigned i )
{
//TODO with iterators
}
template<>
T& tContainer_t::operator[]<T, std::vector<T*> >( unsigned i )
{
// TODO with built in [] operator
}
This is wrong and the compiler doesn't allow this.
Is there a way to make it work, or should I use typeid() to differ the two objects at runtime and act accordingly ?
The way to do it with templates is to make a static helper function in a class that can be partially specialized. However, what I would do is:
template<typename T, typename R>
T& tContainer_t<T, R>::operator[]( unsigned i )
{
//assuming that the container refernce is name container;
typename R::iterator itr = container.begin();
std::advance(itr, i);
return *itr;
}
std::advance is guaranteed that for a container with random access iterators (such as vector), it is constant time (basically, it does iterator + n), it can be as fast as doing the pointer lookup vector performs. Otherwise, it does iterator++ n times, which will be linear time. The const version will use const_iterator, but is essentially the same.
Doing it this way will let you properly handle different types of containers (not just vector and list), without having to modify the code.
You don't have to overload the operator. The library aleady contains overloaded functions to help you. std::advance will move an iterator, taking advantage of operator+() for random access iterators.
template<typename T, typename R>
T& tContainer_t<T, R>::operator[]( unsigned i )
{
typename R::iterator it = myContainer.begin();
std::advance(it, i);
return *it;
}