I have a container, a class, and I would like to provide it with a method assign like STL do.
class myclass {
public:
//...
template < typename InputIterator >
void assign(InputIterator first, InputIterator last);
// ...
private:
// ...
std::vector<int> mystlcont;
// ...
};
template < typename InputIterator >
myclass::assign(InputIterator first, InputIterator last) {
this->mystlcont.clear();
this->mystlcont.assign(first, last);
}
Ok. Well I compile, ok.
I use it now...
myclass m;
std::vector<int> vect;
vect.push_back(1);
vect.push_back(1);
vect.push_back(2);
vect.push_back(3);
vect.push_back(5);
vect.push_back(8);
vect.push_back(13);
m.assign(vect.begin(), vect.end()); // Line X
When calling function at line X, compiler returns a very very ugly error.
workflow_test.hpp: In function ‘void
middleware::WorkflowSerializationTest()’:
workflow_test.hpp:114: error: invalid
cast from type
‘__gnu_cxx::__normal_iterator
’ to type ‘middleware::TaskDescriptor*’
workflow_test.hpp:114: error: invalid
cast from type
‘__gnu_cxx::__normal_iterator
’ to type ‘middleware::TaskDescriptor*’
workflow_test is the file where I am calling the function assign, myclass repreents Workflow class in workflow.hpp and workflow.cpp... TaskDescriptor is the element in the vector (the type in the collection in myclass).
Do you know why this happens?
I suspect that there must be some operator to overload in my class to let this mechanism work correctly.... becaue it is not method implementation the problem, even if I write
template < typename InputIterator >
void myclass::assign(InputIterator first, InputIterator last) {
// NOTHING WRITTEN IN THE BODY
}
When called raises the same exact "exception".
What you have is not your own container, but rather container wrapper.
But I see only one problem with your code: your myclass::assign definition does not have a return type specified.
This code actually works for me:
#include <vector>
#include <algorithm>
#include <iostream>
class MyWrapper {
public:
template <typename InputIterator>
void assign(InputIterator first, InputIterator last);
const std::vector<int>& container() const { return container_m; }
private:
std::vector<int> container_m;
};
template <typename InputIterator>
void MyWrapper::assign(InputIterator first, InputIterator last)
{
container_m.assign(first, last);
}
template <typename T>
void print(const T& x)
{
std::cout << x << " ";
}
int main()
{
MyWrapper mw;
std::vector<int> vect;
vect.push_back(1);
vect.push_back(2);
vect.push_back(3);
vect.push_back(4);
vect.push_back(5);
vect.push_back(6);
vect.push_back(7);
mw.assign(vect.begin(), vect.end());
std::for_each(mw.container().begin(), mw.container().end(), print<int>);
}
Output:
1 2 3 4 5 6 7
Related
I need to create a function which receives the iterator from the begin and the end of one container. Then it should show the content in the console.
My problem is that i dont know how to declare the iterator so that it can work with any type of container
This is what I did:
template <class T>
void print(typename iterator<T> &beg, typename iterator<T> &end) {
while (beg != end) {
cout << *beg << endl;
beg++;
}
}
The std::iterator class is really just a convenience; there's nothing in the standard that requires all iterators to inherit from it. Additionally, std::iterator doesn't have virtual methods, so it's not nearly the same thing as taking an Iterator<T> in, say, Java, where invoking the next() method would call the appropriate next(). You want to take a general type T, not just an std::iterator, so that the compiler will resolve to the correct overloads of operator++ and operator* at compile-time.
template <typename T>
void print(T iter, const T& end) {
// Taking the first argument by value ensures that
// we don't modify the caller's variables
while (iter != end) {
cout << *iter << endl;
++iter;
}
}
This will work for any forward iterators, which is what you're dealing with 99% of the time.
I need to create a function which receives the iterator from the begin
and the end of one container.
Look how standard functions do it, for example std::find:
template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value );
Observations:
InputIt does not need to inherit from the (now obsolete) std::iterator class or any other class. Among other advantages, this allows the function to be used with an array.
The same iterator type is used for start and end.
The iterators are passed by value.
The template parameter does not specify the iterators' value type.
Just do it exactly like that in your own code and you'll be fine:
#include <iostream>
#include <vector>
template <class Iterator> // not T
void print(Iterator beg, Iterator end) {
while (beg != end) {
std::cout << *beg << '\n';
beg++;
}
}
int main() {
std::vector<int> const vec = { 1, 2, 3 };
int const array[] = { 1, 2, 3 };
using std::begin;
using std::end;
print(begin(vec), end(vec));
print(begin(array), end(array));
}
I implemented a templated priority queue:
template<typename TYPE, typename COMP_FUNCTOR = std::less<TYPE>>
class heap_priority_queue : public priority_queue<TYPE, COMP_FUNCTOR> {
public:
typedef unsigned size_type;
template<typename InputIterator>
heap_priority_queue(InputIterator start, InputIterator end, COMP_FUNCTOR comp = COMP_FUNCTOR());
/* other methods*/
};
template<typename TYPE, typename COMP_FUNCTOR>
template<typename InputIterator>
heap_priority_queue<TYPE, COMP_FUNCTOR>::heap_priority_queue (
InputIterator start, InputIterator end, COMP_FUNCTOR comp) {
for(auto it = start; it != end; ++it) {
data.push_back(*it);
}
fix();
this->compare = comp;
}
The default comparison functor defined in the template signature is std::less, but in the constructor of this priority_queue, it seems we can pass another custom COMP_FUNCTOR comp as the 3rd arguments, or we are using the COMP_FUNCTOR declared in the template signature? But when I tried to pass another COMP_FUNCTOR other than the one declared in the template signature as the third argument conflict happens,why? Here is the code:
class isgreater {
public:
isgreater() {};
bool operator () (int a, int b) {
return a > b;
}
};
int main() {
int my_ints[] = {1, 3, 5, 7, 9};
vector<int> v(my_ints, my_ints + sizeof(my_ints)/sizeof(int));
// wrong, default COMP_FUNCOR is std::less, which is different from isgreater;
heap_priority_queue<int> sq(v.begin(), v.end(), isgreater());
// right, no conflict
heap_priority_queue<int, isgreater> back_up(v.begin(), v.end(), isgreater());
Why should the object we pass in as the third argument of the constructor be the same as the one we declare in the template signature? It seems to me make no sense to keep the third argument of the constructor since we must use the one defined in the template signature...Thank you.
// wrong, default COMP_FUNCOR is std::less, which is different from isgreater;
heap_priority_queue<int> sq(v.begin(), v.end(), isgreater());
is equal to
heap_priority_queue<int, std::less<int>> sq(v.begin(), v.end(), isgreater());
and compilator don't know how convert from isgreater to std::less<>
This question already has an answer here:
C++ template won't accept iterators
(1 answer)
Closed 9 years ago.
I'm trying to code a template that takes iterators to any type of vector as its arguments. When I try to compile the following, it gives me a no matching function call error.
#include <vector>
struct A { int x; };
template <class T>
void process (typename std::vector<T>::iterator begin,
typename std::vector<T>::iterator end)
{ for(; begin != end; begin++) { /*do_something*/ } }
int main()
{
std::vector <A> obj;
process(obj.begin(), obj.end());
}
1 the type T cannot be deduced from the argument types.
2 Why would you want to restrict the function to only accept iterators to std::vector elements? If you really only want vector elements, better take std::vector<T> const& as argument. But better simply take any iterator arguments (or any container argument).
edit okay, here is an example. You may omit the static_assert, when this becomes identical (apart from the return type) to std::for_each(begin,end,do_something);
template <class It>
void process(It begin, const It end)
{
static_assert(std::is_same<typename std::iterator_traits<It>::iterator_category,
std::random_access_iterator_tag>::value,
"arguments not random access iterators");
for (; begin != end; ++begin)
do_something(*begin);
}
Per the OP's request, see below. you can use any valid container forward iterator that supports value references from operator *() I.e. a vector, deque, list, etc. This does not employ the static assert logic mentioned by chris, I leave that for you to decide.
#include <iostream>
#include <iterator>
template<typename Iterator>
void process(Iterator start, Iterator stop)
{
typedef typename std::iterator_traits<Iterator>::value_type value_type;
for (Iterator it=start; it != stop; ++it)
{
const value_type& val = (*it);
// do something with val
std::cout << val << std::endl;
}
}
int main()
{
int ar[] = { 1,2,3,4,5 };
process(std::begin(ar), std::end(ar));
return 0;
}
I need to make some specific constructor which gets two iterators: start iterator and end iterator.
I have some code and its works:
#include <iostream>
#include <vector>
using namespace std;
template<typename T>
class A
{
public:
T a[10];
typename std::vector<T>::iterator itStart, itEnd;
A(typename vector<T>::iterator itStart, typename vector<T>::iterator itEnd):itStart(itStart),itEnd(itEnd){}
void see()
{
int i=0;
while(itStart != itEnd)
{
cout<<*itStart<<endl;
a[i] = *itStart;
itStart++;
i++;
}
}
};
template <typename Iterator>
double Sum( Iterator begin, Iterator end );
int main()
{
cout << "Hello world!" << endl;
vector<int> v;
v.push_back(1);
v.push_back(1);
v.push_back(2);
v.push_back(3);
class A<int> a(v.begin(),v.end());
a.see();
return 0;
}
But I want to make constructor arguments work with all STL containers(like Set,List,Map etc.) and with normal arrays(normal pointers).
So can I make it in generic template way? Something like that:
template<typename T>
class A
{
public:
iterator<T> itStart, itEnd;
A(iterator<T> itStart, iterator<T> itEnd):itStart(itStart),itEnd(itEnd){}
void see()
{
while(itStart != itEnd)
{
cout<<*itStart<<endl;
itStart++;
}
}
};
I know code the above is wrong but I want to explain my idea.
Of course I can overload constructor but I am too lazy to that. Too many STL containers.
Is some template way to solve that issue?
Obviously you need to make the iterator type a template argument to your class
template<class T, class Iter>
class A
{
Iter first, last;
A(Iter first, iter last):first(first), last(last){}
};
But now it becomes uncomfortable to explicitly specify the template argument
A<int, vector<int>::iterator > a;
To avoid that, simply create a factory function
template<class T, class Iter>
A<T, Iter> make_A(Iter first, iter last)
{
return A<T, Iter>(first, last);
}
Now, instead of directly creating an object of A, you can use the function
auto my_A = make_A<int>(v.begin(), v.end());
Looking at one of STL's things such as std::fill:
template< class ForwardIt, class T >
void fill( ForwardIt first, ForwardIt last, const T& value );
we can be inspired:
template<typename ITR, typename T>
class A
{
A(ITR itStart, ITR itEnd):itStart(itStart),itEnd(itEnd){}
...
Perhaps you could make use of the notion of an input sequence (iseq).
An input sequence is denoted by a pair of iterators (begin and end).
Of course, you would need to create overloads of all the STL algorithms that accept an iseq instead of a pair of iterators.
Then your example could just use for_each (overloaded to accept an iseq).
Example code can be found in TC++PL 3rd edition (Stroustrup) section 18.3.1.
I have:
void add_all_msgs(std::deque<Message>::iterator &iter);
How can I make that function "generic", so it can take any kind of inputiterators ? I don't really care if it's iterating a deque,a vector or something else, as long as the iterator is iterating Message's. - is this at all straight forward possible in c++ ?
template <typename Iterator>
void add_all_messages(Iterator first, Iterator last)
usage :
vector<message> v;
add_all_messages(v.begin(), v.end());
You need to specify the end, otherwise you won't know when to stop! It also gives you the flexibility of adding only a subrange of a container.
template<class InputIterator>
void add_all_msgs(InputIterator iter);
Usage:
std::deque<Message> deq;
add_all_msgs(deq.begin());
If you want the compiler to check whether the iterator actually refers to Message objects, you can use a technique like the following.
template <typename InputIterator, typename ValueType>
struct AddAllMessages { };
template <typename InputIterator>
struct AddAllMessages<InputIterator, Message> {
static void execute(const InputIterator &it) {
// ...
}
};
template <typename InputIterator>
void add_all_msgs(const InputIterator &it) {
AddAllMessages<InputIterator,
typename std::iterator_traits<InputIterator>::value_type>::execute(it);
}
If you don't want to templatize your add_all_msgs function, you can use adobe::any_iterator:
typedef adobe::any_iterator<Message, std::input_iterator_tag> any_message_iterator;
void add_all_msgs(any_message_iterator begin, any_message_iterator end);
It's difficult to have dynamic polymorphism with C++-style iterators. operator++(int) returns by value, which afaik is intractable: you can't have a virtual member function which returns *this by value without it being sliced.
If possible, I recommend using templates as everyone else says.
However if you do need dynamic polymorphism, for example because you can't expose the implementation of add_all_msgs as a template would do, then I think you could pretend to be Java, like this:
struct MessageIterator {
virtual Message &get() = 0;
virtual void next() = 0;
// add more functions if you need more than a Forward Iterator.
virtual ~MessageIterator() { }; // Not currently needed, but best be safe
};
// implementation elsewhere. Uses get() and next() instead of * and ++
void add_all_msgs(MessageIterator &it);
template <typename T>
struct Adaptor : public MessageIterator {
typename T::iterator wrapped;
Adaptor(typename T::iterator w) : wrapped(w) { }
virtual Message &get() {
return *wrapped;
}
virtual void next() {
++wrapped;
}
};
int main() {
std::deque<Message> v;
Adaptor<std::deque<Message> > a(v.begin());
add_all_msgs(a);
}
I've checked that this compiles, but I haven't tested it and I've never used this design before. I also haven't bothered with const-ness - in practice you probably want a const Message &get() const. And at the moment the adaptor has no way of knowing when to stop, but then neither does the code you started with, so I've ignored that too. Basically you'd need a hasNext function which compares wrapped against an end iterator supplied to the constructor.
You might be able to do something with a template function and const references, so that the client doesn't have to know about or declare that nasty Adaptor type.
[Edit: come to think of it, it's probably better to have a stub add_all_msgs function template, that wraps its parameter in an Adaptor and then calls real_add_all_msgs. This completely hides the adaptor from the client.]
Slightly simpler that the above (in that it leverages existing libraries):
#include <boost/static_assert.hpp> // or use C++0x static_assert
#include <boost/type_traits/is_same.hpp>
template <typename InputIterator>
void add_all_msgs( InputIterator it ) {
BOOST_STATIC_ASSERT(( boost::is_same<
typename std::iterator_traits<InputIterator>::value_type,
Message>::value ));
// ...
#include <deque>
#include <vector>
#include <list>
#include <string>
using namespace std;
template<typename T>
void add_all_msgs(T &iter)
{
}
int _tmain(int argc, _TCHAR* argv[])
{
std::deque<string>::iterator it1;
std::vector<string>::iterator it2;
std::list<string>::iterator it3;
add_all_msgs(it1);
add_all_msgs(it2);
add_all_msgs(it3);
return 0;
}