I am building a stack using arrays (no std::vector allowed) and I must implement a global method that serves as a constructor. The input parameters are two iterators (begin and end) and I have to create a stack from those. The problem is that before i actually create the stack i have to check whether or not is empty. Since I can not pass the stack as a parameter, how am I supposed to call methods on that?
Here is my code:
template <typename IterT>
void method(IterT begin, IterT end) {
try {
if(!is_empty())
make_empty();
for(; begin!=end; ++begin) {
push(static_cast<T>(*begin));
}
}
catch(...) {
clear();
throw;
}
}
Obviously is not working, the methods is_empty(), make_empty(), push() and clear() needs something to work on.
My test method is:
int a[5] = {7, 2, 33, 4, 1111};
stack<int> sp;
sp.push(25); //check if stack is made empty
sp.print();
sp.method(a, a+5);
sp.print();
If it has to be global method that serves as a constructor then what you can do is:
inside stack.h class insert friend declaration for this global method like:
template <typename T>
class stack {
template <typename U, typename IterIt>
friend stack<U> construct(IterIt beg, IterIt end);
private:
T* inside_;
};
In stack.cpp we can now define this construct method:
#include "stack.h"
#include <cstddef>
template <typename T, typename IterIt>
stack<T> construct(IterIt beg, IterIt end) {
// warning: works only with iterators defining binary operator-
stack<T> result;
size_t elems = end - beg;
result.inside_ = new T[elems];
T* add_to = result.inside_;
while (beg != end) {
*add_to = *beg;
++add_to;
++beg;
}
return result;
}
And with simple main method you can have:
int main() {
int a[] = {1,2,3,4,5};
stack<int> s = construct<int>(a, a + 5);
}
I hope this solves your problem. Remember, there might be some corner cases that you would need to solve, but as a baseline I think this should suffice.
Related
I am attempting to write a template function that iterates over a user-specified field within some collection of structs. For example, I want to write the following C++:
struct Example {
int a;
bool b;
};
template<std::function<Field& (Class)> GetField, typename Field, typename Class>
void myFunc(std::iterator<Class> begin, size_t const length) {
cout << length << endl;
for (size_t i{ 0 }; i < length; ++begin, ++i) {
Field const &field{ GetField(*begin) };
// Forward field to some other template function
anotherTemplateFunction<Field>(field);
}
}
void main() {
Example exArray[]{ {5, true}, {8, false} };
std::list<Example> exList{ exArray, exArray + _countof(exArray) }
// Examples of how I would like to call myFunc...
myFunc<Example::a>(exArray, _countof(exArray));
myFunc<Example::b>(exList.begin(), exList.size());
}
The above doesn't work, but hopefully the intent is clear. How can I write the myFunc template method to accomplish generic iteration over some field of each iterated item? Alternatively, if there is some way (in Boost or the Standard Library) to directly create an iterator over exArray[i].a, that would also be acceptable.
What I usually use is something like:
void main() {
std::array<Example, 2> exArray{ {5, true}, {8, false} };
std::list<Example> exList{ exArray.begin(), exArray.end() };
auto access_a = [](Example& e)->int&{ return e.a;};
auto access_b = [](Example& e)->bool&{ return e.b;};
myFunc(exArray.begin(), exArray.end(), access_a);
myFunc(exList.begin(), exList.end(), access_b);
}
template<class ForwardIt, class Accessor>
void myFunc(ForwardIt begin,ForwardIt end, Accessor accessor) {
cout << end - begin << endl;
for (auto it = begin; it != end; it++) {
// Forward field to some other template function
anotherTemplateFunction(accessor(*it));
}
}
Please notice how I used std::array instead of a raw c style array.
If you have access to a c++11 compiler, std::array (or std::vector) should always be preferred over raw c arrays. ES.27
In order to need less boilerplate code, consider using some serialization libraries which solve this "iterating over class fields" problem, for example boost serialization or magic get.
It's simple if you know the pointer to member syntax and the likes. Unfortunately is so rarely used, is kind of an esoteric feature of the language:
template <class T> void foo(T);
template <auto Field, class It>
auto myFunc(It begin, It end)
{
for (; begin != end; ++begin)
{
foo((*begin).*Field);
}
}
int main()
{
std::vector<Example> v{{5, true}, {8, false}};
myFunc<&Example::a>(v.begin(), v.end()); // will call foo<int>(5) , foo<int>(8)
myFunc<&Example::b>(v.begin(), v.end()); // will call foo<bool>(true) , foo<bool>(false)
}
For the template <auto Field you need C++17.
For C++11 the syntax is more verbose:
template <class T, class F, F T::* Field, class It>
void myFunc(It begin, It end)
{ /* same */ }
int main()
{
std::vector<Example> v{{5, true}, {8, false}};
myFunc<Example, int, &Example::a>(v.begin(), v.end()); // will call foo<int>(5) , foo<int>(8)
myFunc<Example, bool, &Example::b>(v.begin(), v.end()); // will call foo<bool>(true) , foo<bool>(false)
}
A little bit OT to your question, but I don't understand why you complicate yourself with that initialization of std::list. In C++ your first container of choice should be std::vector.
Also there is no std::iterator
I am trying to generalize a function I have which used to take two iterators to a vector of a specific data-structure, and re-arrange the elements in a certain way using std::iter_swap (like std::sort does).
Since this function only actually needs a subset of the data, and I will need to use it in other contexts in the future, I thought about removing the dependency on the data structure, and use boost::transform_iterator at the point of call to handle the transformation.
Unfortunately, it seems that boost::transform_iterator is not happy with this change. I can imagine why: std::iter_swap is usually implemented as std::swap(*lhs, *rhs), and dereferencing the transform_iterator does not yield the original element to swap in the correct way.
I was wondering if there was a way to handle this case. I am open to use boost::range or the experimental std::ranges ts if it needed.
This question is probably similar to this one, but even there the solution ends up modifying the subset of data the algorithm needs, rather than the outside structure.
Here is an MWE:
#include <boost/iterator/transform_iterator.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
struct A {
int x;
int y;
};
template <typename It>
void my_invert(It begin, It end) {
while (begin < end) {
std::iter_swap(begin++, --end);
}
}
template <typename It>
void my_print(It begin, It end) {
for (; begin != end; ++begin)
std::cout << (*begin) << ' ';
std::cout << '\n';
}
int main() {
std::vector<int> x{7,6,5,4,3,2};
my_invert(std::begin(x), std::end(x));
my_print(std::begin(x), std::end(x));
auto unwrap = +[](const A & a) { return a.x; };
std::vector<A> y{{9,8}, {7,6}, {5,4}, {3,2}};
auto begin = boost::make_transform_iterator(std::begin(y), unwrap);
auto end = boost::make_transform_iterator(std::end(y), unwrap);
//my_invert(begin, end); // Does not work.
my_print(begin, end);
return 0;
}
Accessing the underlying iterator
You could access the base() property of transform_iterator (inherited publicly from iterator_adaptor) to implement your custom transform_iter_swap, for swapping the underlying data of the wrapped iterator.
E.g.:
template<class IteratorAdaptor>
void transform_iter_swap(IteratorAdaptor a, IteratorAdaptor b)
{
std::swap(*a.base(), *b.base());
}
template <typename It>
void my_invert(It begin, It end) {
while (begin < end) {
transform_iter_swap(begin++, --end);
}
}
After which your example (omitting the std::vector part) runs as expected:
my_invert(begin, end); // OK
my_print(begin, end); // 3 5 7 9
If you want a general function template to cover both the boost (adaptor) iterators as well as typical iterators, you could e.g. use if constexpr (C++17) based on whether the iterators public typedef iterator_category derives from boost::iterators::no_traversal_tag or not:
// expand includes with
#include <boost/iterator/iterator_categories.hpp>
template <class It>
void iter_swap(It a, It b) {
if constexpr(std::is_base_of<
boost::iterators::no_traversal_tag,
typename It::iterator_category>::value) {
std::swap(*a.base(), *b.base());
}
else {
std::swap(*a, *b);
}
}
template <typename It>
void my_invert(It begin, It end) {
while (begin < end) {
iter_swap(begin++, --end);
}
}
The problem comes from the unary predicate you've passed. Notice, that since you allow the return type to be deduced, the return type is deduced to be an int, a copy is returned, and the compilation fails when you try to swap two unmodifiable ints. However, if you were to specify the return type to be int&, like so:
auto unwrap = [](A & a)->int& { return a.x; }; // explicitly demand to return ref
It will compile, and reverse the elements. Tested on gcc 8.1.0 and clang 6.0.0.
I need to create a method that receives iterators as arguments and return a templated collection of the same type.
I created a minimal example the demonstrates my need:
#include <list>
#include <iostream>
using namespace std;
class A {
int i;
public:
A(int _i) : i(_i) {}
operator int() {
return i;
}
};
class B {
int i;
public:
B(int _i) : i(_i) {}
operator int() {
return i;
}
};
template <class T>
list<T> method(typename list<T>::iterator begin, typename list<T>::iterator end) {
list<T> res; // I need the template class here
for (; begin != end; begin++) {
cout << *begin; // Whatever...
}
return res;
}
int main() {
list<A> listA = {1, 2, 3};
list<B> listB = {4, 5, 6};
auto res1 = method(listA.begin(), listA.end()); // Cannot change
auto res2 = method(listB.begin(), listB.end()); // Cannot change
}
This is not a working example, but I am looking for a way to make this work.
The important part is the method and it's arguments, and that it will return a templated class with T. So I can change the method as much as i want but the auto res1 = method(listA.begin(), listA.end()); should stay the same. (not my code)
How can I do something like this?
In this particular case (if you know that it's std::list) you can get value_type from iterator itself:
template <class T>
auto method(T begin, T end) {
list<typename T::value_type> res; // I need the template class here
for (; begin != end; begin++) {
cout << *begin; // Whatever...
}
return res;
}
value_type = U only for std::list<U>
typename list<T>::iterator is a non-deduced context. You need to either pass the container itself or specify it as an explicit template argument.
Iterators designate a sequence; they do not have to be associated with a "collection". For example, you can create an iterator that reads input from the console.
If you want to restrict a function to only work with containers, then write it that way:
template <class T>
T f(const T& container) {
// whatever; code that uses begin() and end()?
}
This isn't possible. You can have iterators that don't correspond to any container. The function that calls method should create an empty list and pass a back_inserter to the list as the third argument to method. Use std:copy as an example of what your method should look like.
I'm sorry this must be a really simple question...
I'm a beginner of C++ and I was trying to write a trivial quicksort function using function template.
#include <iostream>
#include <vector>
using namespace std;
template <class iterator, class val>
void move_to_front(iterator movethis, iterator leftend) {
val temp = *movethis; // hold the element being moved
for (iterator i = movethis; i != leftend; i--) {
*i = *(i-1);
} // all other elements shift right
*leftend = temp; // put it back to the front
}
template <class iterator>
void qsort(iterator begin, iterator end) {
iterator oldbegin = begin;
for (iterator i = begin + 1; i != end; i++) {
if (*i <= *begin) {
move_to_front(i, begin);
oldbegin++;
}
} // move elements smaller than or equal to the first element
// to the left of the first element.
// oldbegin indicates the first element, so it + 1 every time an
// element is moved to its left.
qsort(begin, oldbegin);
qsort(oldbegin, end);
}
int main(int argc, char const *argv[]) {
int test[] = {8,7,2,4,1,4,5,4,2};
vector<int> ar(test, test+9);
qsort(ar.begin(), ar.end());
for (vector<int>::iterator i = ar.begin(); i != ar.end(); i++) cout << *i;
return 0;
}
The compiler complains
/Users/Larry_Li/Project Euler/foo.cpp:20:11: error: no matching function for call to 'move_to_front'
move_to_front(i, begin);
^~~~~~~~~~~~~
/Users/Larry_Li/Project Euler/foo.cpp:31:7: note: in instantiation of function template specialization 'qsort<std::__1::__wrap_iter<int *> >' requested here
qsort(ar.begin(), ar.end());
^
/Users/Larry_Li/Project Euler/foo.cpp:6:10: note: candidate template ignored: couldn't infer template argument 'val'
void move_to_front(iterator movethis, iterator leftend) {
^
1 error generated.
I think I was defining the template wrong somehow... especially the val part in template <class iterator, class val>,
May I ask how to make it work?
The problem is that the compiler cannot deduce one of your template arguments here:
template <class iterator, class val>
void move_to_front(iterator movethis, iterator leftend) {
val temp = *movethis; // hold the element being moved
There is no function parameter of type val, so there's no way for the compiler to know what that type should be. But you don't need it anyway. If you have C++11 available, you could use auto, as Scooby suggested. Otherwise, you could use std::iterator_traits to get the value type from the iterator type:
template <class iterator>
void move_to_front(iterator movethis, iterator leftend) {
typename std::iterator_traits<iterator>::value_type temp = *movethis;
This probably won't help directly, as you appear to be intentionally reinventing the wheel, and/or using this scenario to test and expand your template knowledge rather than to solve the exact problem your code is written to solve. But just in case all you want to do is implement move_to_front, consider std::rotate:
#include <algorithm>
template <class iterator>
void move_to_front(iterator movethis, iterator leftend) {
std::rotate(leftend, movethis, movethis + 1);
}
You may also want to consider changing the order of your arguments to be more in line with the STL, but that's up to you. See a live example (the example uses C++11 but the function does not require it).
Try this, assuming you are using C++11:
template <class iterator>
void move_to_front(iterator movethis, iterator leftend) {
auto temp = *movethis; // hold the element being moved
for (iterator i = movethis; i != leftend; i--) {
*i = *(i-1);
} // all other elements shift right
*leftend = temp; // put it back to the front
}
But, in my opinion, I thik you're overcomplicating with all the iterators.
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;
}