Returning a vector from a function - c++

So I wrote a class in a header file called: main.h and I want to return the vector after calling the function. So here is the code for the header file:
//main.h
#include <iostream>
#include <vector>
#include <string>
template <typename T1>
class LSR {
public:
std::vector<T1> arr;
LSR(std::vector<T1> ARR) {
arr = ARR;
}
// template <typename T2>
void output() {
for (int i=0; i<arr.size(); i++) {
std::cout << arr[i] << std::endl;
}
}
template <typename T2>
int search(T2 to_find) {
for (int i=0; i<arr.size(); i++) {
if (arr[i] == to_find) { return i; }
}
return -1;
}
template <typename T3>
T1 replace(T3 to_find, T1 to_replace) {
int value = search(to_find);
if (value > -1) {
for (int x=0; x<arr.size(); x++) {
arr[x] = to_replace;
}
return std::vector<T1> arr; <-- error here
}
return NULL;
}
};
//main.cpp
#include "main.h"
int main() {
std::vector<std::string> board = {
"Hello", "there",
"how", "are", "you"
};
LSR<std::string> L1(board);
L1.replace("you", "yeah ya");
std::cout << board[4] << std::endl;
return 0;
}
And I have tried 2 things that I can think of but it didn't work:
just returning arr but that didn't work, it has the following errors:
expected primary-expression before 'arr'
expected ';' before 'arr'
Returning std::vector<T1> only, with the following error:
expected primary-expression before ';' token
I am unsure what I need to do to solve this problem, as I ran out of ideas.

replace() can't return the entire arr. For one thing, the syntax you are using is wrong, return std::vector<T1> arr; would need to be return arr; instead. But replace() returns a T1, and arr is not a T1 but a std::vector<T1> instead, so return'ing arr won't work.
In any case, there is no need to have replace() return anything at all, since it is modifying the contents of this.
Also, replace() is not actually replacing the found element correctly, it is replacing all elements in the arr if any of them match to_find.
You need to get rid of the loop altogether if you want to replace only the 1st matching element, eg:
template <typename T3>
void replace(const T3 &to_find, const T1 &to_replace) {
int value = search(to_find);
if (value > -1) {
arr[value] = to_replace;
}
}
Otherwise, get rid of the search() call if you want to replace all matching elements, eg:
template <typename T3>
void replace(const T3 &to_find, const T1 &to_replace) {
for (size_t x = 0; x < arr.size(); ++x) {
if (arr[i] == to_find) {
arr[i] = to_replace;
}
}
}
That being said, there is no reason to have all of the class methods use their own template parameters, since they all operate on the same type as the main template parameter of the class, so just use that one template by itself for everything, eg:
#include <iostream>
#include <vector>
template <typename T>
class LSR {
public:
std::vector<T> arr;
LSR(const std::vector<T> &ARR) {
arr = ARR;
}
void output() const {
for (size_t i = 0; i < arr.size(); ++i) {
std::cout << arr[i] << std::endl;
}
}
int search(const T &to_find) const {
for (size_t i = 0; i < arr.size(); ++i) {
if (arr[i] == to_find) { return i; }
}
return -1;
}
void replace(const T &to_find, const T &to_replace) {
// see further above...
}
};
Also, the class constructor makes a copy of the board array, so when main() outputs board[4], it is not going to see the result of replace(). main() would have to access the modified arr instead, eg:
#include <iostream>
#include <string>
#include "main.h"
int main() {
std::vector<std::string> board = {
"Hello", "there",
"how", "are", "you"
};
LSR<std::string> L1(board);
L1.replace("you", "yeah ya");
std::cout << L1.arr[4] << std::endl;
return 0;
}
Otherwise, change the class to keep a reference to the board vector, instead of making a copy of it, then board[4] will get modified as expected, eg:
#include <iostream>
#include <vector>
template <typename T>
class LSR {
public:
std::vector<T> &arr;
LSR(std::vector<T> &ARR) : arr(ARR) {}
...
};
#include <iostream>
#include <string>
#include "main.h"
int main() {
std::vector<std::string> board = {
"Hello", "there",
"how", "are", "you"
};
LSR<std::string> L1(board);
L1.replace("you", "yeah ya");
std::cout << board[4] << std::endl;
return 0;
}

Related

What is this error? "no matching function for call to 'foreach(std::array<int, 4>&, void(&)(int))"

I created a foreach() function, and it should print values of an array, but it tells me this:
no matching function for call to 'foreach(std::array<int, 4>&, void(&)(int))'
And also:
mismatched types 'unsigned int' and 'long unsigned int'
But when I try to use vectors instead of arrays, or on line 11 use template<unsigned int N> instead of unsigned int, if I use long unsigned int, it works fine.
So, why do I need to use long unsigned int?
And what does the "no matching function" error mean with arrays?
#include<iostream>
#include<string>
#include<array>
typedef void(*func)(int);
void print(int value) {
std::cout << "value is : " << value << std::endl;
}
template<unsigned int N>
void foreach(std::array<int, N>& values, func print) {
int value;
for(int i = 0; i < values.size(); i++) {
value = values[i];
print(value);
}
}
int main() {
std::array<int, 4> arr = { 0, 1, 2, 3 };
foreach(arr, print);
return 0;
}
With vectors:
#include<iostream>
#include<string>
#include<vector>
typedef void(*func)(int);
void print(int value) {
std::cout << "value is : " << value << std::endl;
}
void foreach(std::vector<int>& values, func print) {
int value;
for(int i = 0; i < values.size(); i++) {
value = values[i];
print(value);
}
}
int main() {
std::vector<int> v = { 0, 1, 2, 3 };
foreach(v, print);
return 0;
}
The template for std::array does not take an unsigned int, it takes a std::size_t, which may or may not (probably not) be defined as unsigned int:
template<size_t N>
void foreach(std::array<int, N>& values, func print);
A better option is to make your function be container-agnostic instead, by passing it iterators instead of the actual container, eg:
#include <iostream>
#include <string>
#include <array>
#include <vector>
typedef void(*func)(int);
void print(int value) {
std::cout << "value is : " << value << std::endl;
}
template<typename Iter>
void foreach(Iter begin, Iter end, func print) {
while (begin != end) {
print(*begin);
++begin;
}
}
int main() {
std::array<int, 4> arr = { 0, 1, 2, 3 };
foreach(arr.begin(), arr.end(), print);
std::vector<int> v = { 0, 1, 2, 3 };
foreach(v.begin(), v.end(), print);
return 0;
}
Not only does this allow the function to work with multiple containers, but also with different element types, if you change the print parameter to be a template as well, eg:
#include <iostream>
#include <string>
#include <array>
#include <vector>
void printInt(int value) {
std::cout << "value is : " << value << std::endl;
}
void printStr(const std::string &value) {
std::cout << "value is : " << value << std::endl;
}
template<typename Iter, typename Callable>
void foreach(Iter begin, Iter end, Callable print) {
while (begin != end) {
print(*begin);
++begin;
}
}
int main() {
std::array<int, 4> arr = { 0, 1, 2, 3 };
foreach(arr.begin(), arr.end(), printInt);
std::vector<std::string> v = { "hello", "world", "joe", "smoe" };
foreach(v.begin(), v.end(), printStr);
return 0;
}
This is the exact strategy that standard algorithms use, such as std::for_each() (which you should be using instead of writing your own) 1, eg:
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <algorithm>
int main() {
std::array<int, 4> arr = { 0, 1, 2, 3 };
std::for_each(arr.begin(), arr.end(),
[](int value) { std::cout << "value is : " << value << std::endl; }
);
std::vector<std::string> v = { "hello", "world", "joe", "smoe" };
std::for_each(v.begin(), v.end(),
[](const std::string &value) { std::cout << "value is : " << value << std::endl; }
);
return 0;
}
1: C++20 introduced a new Ranges library that has algorithms to act on whole containers.
Because the second template parameter for std::array is std::size_t, not unsigned int. Compiler cannot infer the convertion between types in template function. And it just happens that std::size_t in your compiler is a typedef on long unsigned int, so that's what it suggests.
You can make it work in two ways:
Change the template type to std::size_t
Provide template parameter explicitly when calling:
foreach<4>(v, print);

Unify the express of a complex number in initializer list and istream field

As an old c99 person, I was often stubled upon the curly brakets initialization. In the `initializer_list`, I have to use {r, i} for a complex number. On the other hand, I have to use (r, i) for `complex` in the istream field. Here, I cut a part of my class that is able to run and give examples under codeblock 20.03 with MinGW 8.1.0.
#ifndef __tMatrix_class__
#define __tMatrix_class__
#include <iostream>
#include <initializer_list>
#include <iomanip>
#include <complex>
#include <sstream>
template <typename T> class tMatrix
{
public:
T *ptr;
int col, row, size;
inline T* begin() const {return ptr;}
inline T* end() const {return this->ptr + this->size;}
inline T operator()(const int i, const int j) const { return ptr[i*col+j]; } // r-value
inline T&operator()(const int i, const int j) { return ptr[i*col+j]; } //l-value
inline tMatrix(): col{0}, row{0}, size{0}, ptr{0} {;}
tMatrix(const int i, const int j): col(j), row(i), size(i*j) {
ptr = new T [this->size] ; }
tMatrix(const std::initializer_list< std::initializer_list<T> > s):tMatrix<T>(s.size(), s.begin()->size())
{
int j = 0;
for (const auto& i : s) { std::copy (i.begin(), i.end(), ptr + j*col); ++j ; }
}
tMatrix(const tMatrix<T>&a) : tMatrix<T>(a.row, a.col)
{
std::copy(a.begin(), a.end(), this->ptr);
}
tMatrix<T>& operator=(tMatrix<T>&&a)
{
this->col = a.col;
this->row = a.row;
delete [] this->ptr;
this->ptr = a.ptr;
a.ptr = nullptr;
return *this;
}
tMatrix<T>& operator=(const tMatrix<T>&a)
{
if (col==a.cpl && row==a.row) std::copy(a.begin(), a.end(), this->ptr);
else { tMatrix<T>&&v(a); *this = std::move(v);}
return *this;
}
tMatrix<T>& operator=(const std::initializer_list<std::initializer_list<T> > a)
{
tMatrix<T> &&v = a;
*this = std::move(v);
return *this;
}
~tMatrix() {delete [] this->ptr;}
void operator<<(const char*s)
{
std::stringstream ss;
ss.str(s);
for (int i=0; i<this->size; i++){
if (ss.good()) ss >> this->ptr[i];
else return;
}
}
}; //end of class tMatrix
template <typename X> std::ostream& operator<<(std::ostream&p, const tMatrix<X>&a)
{
p << std::fixed;
for (int i=0; i<a.row; i++) {
for (int j=0; j <a.col; j++) p << std::setw(12) << a(i, j);
p << std::endl;
}
return p;
}
using CMPLX = std::complex<double>;
using iMatrix = tMatrix<int>;
using rMatrix = tMatrix<double>;
using cMatrix = tMatrix< CMPLX >;
#endif
int main()
{
cMatrix cx(2,2);
cx = { { {1,2},{3,4} }, { {5,6}, {7,8} } };
std::cout << cx << std::endl;
cx << "(1,2) (3,4)";
std::cout << cx << std::endl;
return 0;
}
The above code renders correct format of complex number, and prints
$ ./ttt_mtx_init_fin_tmp.exe
(1.000000,2.000000)(3.000000,4.000000)
(5.000000,6.000000)(7.000000,8.000000)
(1.000000,2.000000)(3.000000,4.000000)
(5.000000,6.000000)(7.000000,8.000000)
But if I use the `()` in the initializer_list and `{}` in the istream filed, the results are all wrong. If I chagned the relavant part of main() to :
cx = { { (1,2),(3,4) }, { (5,6), (7,8) } };
std::cout << cx << std::endl;
cx << "{1,2} {3,4}";
std::cout << cx << std::endl;
Which renders all wrong values (compared with above):
$ ./ttt_mtx_init_fin_tmp.exe
(2.000000,0.000000)(4.000000,0.000000)
(6.000000,0.000000)(8.000000,0.000000)
(2.000000,0.000000)(4.000000,0.000000)
(6.000000,0.000000)(8.000000,0.000000)
I found it is rather confusion. So, my questions: is there a way to make these two expressions a same form? Many thanks for any helps.
I do not know any way to make std::istream::operator>> use { and } for std::complex, but if you are fine with using a helper, then you can replace the () in the input with {} and forward the input to the original operator>>:
#include <iostream>
#include <complex>
#include <sstream>
#include <algorithm>
template <typename T>
struct complex_reader {
std::complex<T>& target;
};
template <typename T>
complex_reader<typename T::value_type> get_complex_reader(T& t){ return {t};}
template <typename T>
std::istream& operator>>(std::istream& in,complex_reader<T> cr){
std::string input;
std::getline(in,input,'}'); // read till `}`
std::replace(input.begin(),input.end(),'{','(');
input += ')';
std::stringstream ss{input};
ss >> cr.target; // call the original >>
return in;
}
int main()
{
std::stringstream ss{"{2,2}"};
std::complex<double> x;
ss >> get_complex_reader(x);
std::cout << x;
}
Output:
(2,2)
However, you would have to write a similar helper to get consistent output (you may not provide an operator<< for std::complex<T> directly). Also note that the above implementation is a little simplistic. It reads from the stream until it encounters a }. For invalid input this may result in undesired effects and more sophisticated input validation is required.
Note that the operator>> takes the complex_helper by value to allow passing temporaries. Thats fine, because the member is a (non-const) reference.
This is not an answer, but a reasoning of my choice. After a series of cross conversions with `largest_prime_is_463035818`, I figured out what is my best choice for now (many thanks to his time and patience). A bottom line is becoming clear to me that I will not alter the input format of istream that is too much changed for pratical purpose, since file input is the major method to fetch data for a large matrix.
Under this constrain, I try to make the appearance of initializer_list as friendly as possible. I did some experiments, and found that the complex_literals expression is acceptable by initializer_list. And it looks ok to me.
using namespace std::complex_literals;
int main()
{
cMatrix cx(3,2);
cx = { { 1+2.2j , 4j}, { 5.3+6.5j , 8.3j}, {8.3, 5.6+4j} };
std::cout << cx << std::endl;
cx << " (1,2) (3,4) (5,6) (7,8) (2.3, 3.4) (2,7.8) ";
std::cout << cx << std::endl;
return 0;
}
And it works.
$ ./a.exe
(1.000000,2.200000) (0.000000,4.000000)
(5.300000,6.500000) (0.000000,8.300000)
(8.300000,0.000000) (5.600000,4.000000)
(1.000000,2.000000) (3.000000,4.000000)
(5.000000,6.000000) (7.000000,8.000000)
(2.300000,3.400000) (2.000000,7.800000)
Thank you for your patience, and please let me know if there are better ways.

Why is trying to store a pointer to function ambiguous

Here is my code:
#include <functional>
#include <iostream>
#include<vector>
using namespace std;
// vector iterator
template <class T> class vit
{
private:
//vector<T>::iterator it;
vector<T> m_v;
function<bool (T, T)> m_fptr;
int len, pos;
public:
vit(vector<T> &v) { this->m_v = v; len = v.size(); pos = 0;};
// it= v.begin(); };
bool next(T &i) {
//if(it == m_v.end()) return false;
if(pos==len) return false;
//i = *it;
i = m_v[pos];
//if(idle) { idle = false ; return true; }
//it++;
pos++;
return true;};
//bool idle = true;
void set_same(function<bool (T,T)> fptr) { m_fptr = fptr ;};
//void set_same(function<bool(int, int)> fun) { return ; }
bool grp_begin() {
return pos == 0 || ! m_fptr(m_v[pos], m_v[pos-1]); };
bool grp_end() {
return pos == len || ! m_fptr(m_v[pos], m_v[pos+1]); };
};
bool is_same(int a, int b) { return a == b; }
main()
{
vector<int> v ={ 1, 1, 2, 2, 2, 3, 1, 1, 1 };
int total;
for(auto it = v.begin(); it != v.end(); it++) {
if(it == v.begin() || *it != *(it-1)) {
total = 0;
}
total += *it;
if(it+1 == v.end() || *it != *(it+1)) {
cout << total << endl;
}
}
cout << "let's gry a group" <<endl;
vit<int> g(v);
int i;
while(g.next(i)) { cout << i << endl; }
cout << "now let's get really fancy" << endl;
vit<int> a_vit(v);
//auto is_same = [](int a, int b) { return a == b; };
a_vit.set_same(is_same);
//int total;
while(a_vit.next(i)) {
if(a_vit.grp_begin()) total = 0;
total += i;
if(a_vit.grp_end()) cout << total << endl ;
}
}
When I compile it with g++ -std=c++11 iter.cc -o iter, I get the result:
iter.cc: In function 'int main()':
iter.cc:63:17: error: reference to 'is_same' is ambiguous
a_vit.set_same(is_same);
^
iter.cc:37:6: note: candidates are: bool is_same(int, int)
bool is_same(int a, int b) { return a == b; }
^
In file included from /usr/include/c++/5.3.0/bits/move.h:57:0,
from /usr/include/c++/5.3.0/bits/stl_pair.h:59,
from /usr/include/c++/5.3.0/utility:70,
from /usr/include/c++/5.3.0/tuple:38,
from /usr/include/c++/5.3.0/functional:55,
from iter.cc:1:
/usr/include/c++/5.3.0/type_traits:958:12: note: template<class, class> struct std::is_same
struct is_same;
^
By way of explanation, I have created a class called 'vit'. It does two things: iterate over a vector, and determine if a new group has been reached.
The class function 'set_same' is supposed to store a function provided by the calling class to determine if two adjacent elements of a vector are in the same group. However, I can't seem to store the function in the class for future use by grp_begin() and grp_end() on account of the ostensible ambiguity of is_same.
What gives?
There is an is_same function defined by you and there is a struct is_same defined by the C++ Standard Library. Since you are using namespace std, your compiler doesn't know which is_same you meant to use.
It's what the error says: it's not clear whether you mean your is_same (in the global namespace) or the class template is_same (in namespace std).
You may disambiguate as follows:
::is_same
… with the leading :: meaning "in the global namespace".
Though you should consider putting your code in a namespace of its own.
Thanks guys. This is my first time touching C++ after more than a decade. I have cleaned up the code, and used a lambda to bring the "is_same" function closer to where it is called.
Did you spot the bug in my code? 'pos' was off-by-one when calling grp_begin() and grp_end(). Here is the revised code:
#include <functional>
#include <iostream>
#include <vector>
// vector iterator
template <class T> class vit
{
private:
std::vector<T> m_v;
std::function<bool (T, T)> m_fptr;
int len, pos;
public:
vit(std::vector<T> &v) { m_v = v; len = v.size(); pos = -1;};
bool next(T &val) {
pos++;
if(pos==len) return false;
val = m_v[pos];
return true;};
void set_same(std::function<bool (T,T)> fptr) { m_fptr = fptr ;};
bool grp_begin() {
return pos == 0 || ! m_fptr(m_v[pos], m_v[pos-1]); };
bool grp_end() {
return pos+1 == len || ! m_fptr(m_v[pos], m_v[pos+1]); };
};
main()
{
std::vector<int> v ={ 1, 1, 2, 2, 2, 3, 1, 1, 1 };
vit<int> a_vit(v);
std::function<bool (int, int)> is_same = [](int a, int b) { return a == b; };
a_vit.set_same(is_same);
int i, total;
while(a_vit.next(i)) {
if(a_vit.grp_begin()) total = 0;
total += i;
if(a_vit.grp_end()) std::cout << total << std::endl ;
}
}
My class definition isn't bullet-proof and could be better: if the user forgets to 'set-same', for example, they'll be referring a random memory address as a function.
Nevertheless, I'm pretty chuffed with my solution so far. The class caller is relieved of all the bookkeeping relating iterating over the vector, and working out if a group boundary has been crossed.
The calling code looks very compact and intuitive to me.I can see C++ being my go to language.

lambda parameter with optional return value

I'm trying to write a function like std::for_each, that in addition to the normal usage, can also take a std::function<bool (param)>. A false return value means that I want to break out of the loop. The code below is what I've gotten so far.
The second call to a.visit([&](int) -> void) does not compile when evaluating !visitor(i). Is it possible to make this work or am I barking up the wrong tree?
I'm using MSVC 2010 but want the code to be generally C++11 compatible.
#include <list>
#include <string>
#include <iostream>
struct A
{
std::list<int> _lst;
template<typename _F>
void visit(_F visitor)
{
for(std::list<int>::const_iterator it = _lst.begin(), end = _lst.end() ; it != end ; it++) {
int i = *it;
if (std::is_void<decltype(visitor(i))>::value) {
visitor(i);
} else {
if (!visitor(i)) { // <----- error C2171: '!' : illegal on operands of type 'void'
break;
}
}
}
}
};
int main(int argc, char* argv[])
{
A a;
// populate a
for (int i = 0 ; i < 10 ; i++) {
a._lst.push_back(i);
}
a.visit([](int i) -> bool {
std::cout << i << std::endl;
return i < 5;
});
a.visit([](int i) {
std::cout << i << std::endl;
});
}
Here's how I would implement for_almost_each; I'm using namespace std plus type aliases for readability purposes.
#include <algorithm>
#include <iterator>
#include <functional>
using namespace std;
template<class Iter, class Func>
Iter
for_almost_each_impl(Iter begin, Iter end, Func func, std::true_type)
{
for (auto i = begin; i!=end; ++i)
if (!func(*i))
return i;
return end;
}
template<class Iter, class Func>
Iter
for_almost_each_impl(Iter begin, Iter end, Func func, std::false_type)
{
for_each(begin, end, func);
return end;
}
template<class Iter, class Func>
Iter for_almost_each(Iter begin, Iter end, Func func)
{
using Val = typename iterator_traits<Iter>::value_type;
using Res = typename result_of<Func(Val)>::type;
return for_almost_each_impl(begin, end,
func,
is_convertible<Res, bool>{} );
}
I used is_convertible, as it seems to make more sense than is_same.
Your std::is_void needs to be done at compile time and can't be done inside the function body. This use of function overloading will work:
#include <list>
#include <string>
#include <iostream>
#include <type_traits> // missing header
struct A
{
std::list<int> _lst;
// wrapper for bool returning visitor
template<typename _F, typename Iter>
bool do_visit(_F visitor, Iter it, std::true_type)
{
return visitor(*it);
}
// wrapper for non-bool returning visitor
template<typename _F, typename Iter>
bool do_visit(_F visitor, Iter it, std::false_type)
{
visitor(*it);
return true;
}
template<typename _F>
void visit(_F visitor)
{
for (auto it = _lst.begin(), end = _lst.end() ; it != end ; it++) {
// select correct visitor wrapper function using overloading
if (!do_visit(visitor, it, std::is_same<bool, decltype(visitor(0))>())) {
break;
}
}
}
};
int main(int argc, char* argv[])
{
A a;
// populate a
for (int i = 0 ; i < 10 ; i++) {
a._lst.push_back(i);
}
a.visit([](int i) -> bool {
std::cout << i << std::endl;
return i < 5;
});
a.visit([](int i) {
std::cout << i << std::endl;
});
}
This lambda doesn't return a value, which is why you're getting an error that "visitor" is returning void:
a.visit([](int i) {
std::cout << i << std::endl;
});
You could make this work by rewriting as:
a.visit([](int i) -> bool {
std::cout << i << std::endl;
return true;
});

how to call a templetized vector of records

I'm having a problem getting the syntax right so if someone can help,please?
I have a timing function which take a function and its arguments as a parameters, but I'm not sure how should the call look like.
#include <iostream>
#include <iterator>
#include <random>
#include <vector>
#include<list>
#include<deque>
#include <algorithm>
#include <chrono>
#include <functional>
#include <sstream>
using namespace std;
using namespace std::chrono;
int global_SortType = 1;
template<class F, class A, typename T>
void times(F func, A arg, int n, T typeval) // call func(arg,n)
{
auto t1 = system_clock::now();
func(arg, n, typeval);
auto t2 = system_clock::now();
auto dms = duration_cast<milliseconds>(t2-t1);
cout << "f(x) took " << dms.count() << " milliseconds\n";
}
template<class T>
bool Greater(const T& v1, const T& v2)
{
return false;
}
bool Greater(const int& v1, const int& v2)
{
return v1 > v2;
}
bool Greater(const string& v1, const string& v2)
{
return strcmp(v1.c_str(), v2.c_str()) > 0;
}
template <class T>
struct GreaterThan: public std::binary_function<T, T, bool > {
bool operator () ( const T &ival, const T &newval ) const {
return Greater(ival, newval);
}
};
string random_gen(string& s)
{
string Result; // string which will contain the result
ostringstream convert; // stream used for the conversion
convert << rand();
return convert.str();
}
int random_gen(int& i){
default_random_engine re { std::random_device()() };
uniform_int_distribution<int> dist;
auto r= bind(dist,re);
int x =r();
return x;
}
template<class T>
void print(T& val)
{
}
void print(int& val)
{
cout << val << " ";
}
void print(string& val)
{
cout << val.c_str() << " ";
}
struct Record
{
int v;
string s;
Record(){}
Record(int iv, string ss): v(iv), s(ss)
{
}
};
Record random_gen(Record& r)
{
string stemp;
int i = 0;
return Record(random_gen(i), random_gen(stemp));
}
void print(Record& r)
{
cout<<"int="<<r.v<<" string=";
print(r.s);
}
bool Greater(const Record& r1, const Record& r2)
{
return global_SortType == 1 ? Greater(r1.v, r2.v) : Greater(r1.s, r2.s);
}
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
{
for(int i=0; i!=n; ++i) {
T gen = random_gen(valtype);
typename SequenceContainer::const_iterator it;
it=find_if(seq.begin(), seq.end(), std::bind2nd(GreaterThan<T>(), gen));
seq.insert(it, gen);
}
for(int i=n-1; i >=0; i--)
{
int gen = i;
if(i > 0)
gen = random_gen(i)%i;
typename SequenceContainer::const_iterator it=seq.begin();
for(int j = 0; j < gen; j++)
it++;
seq.erase(it);
}
}
int main()
{
int n=1000;
vector<int> v;
times(build_cont<std::vector<int>, int>, v, n, 0); // works
vector<string> sv;
string stemp = "";
times(build_cont<std::vector<string>, string>, sv, n, stemp); // works
global_SortType = 1;
vector<Record> rv;
Record rtemp(0, "sfds");
global_SortType = 2;
vector<Record> rsv;
Record rstemp(0, "sfds");
//This one desn't work and I'm not sure of the right syntax
times(build_cont<std::vector<Record>,Record>, sv, n, stemp);
return 0;
}
I'm getting this error
Non-const lvalue reference to type 'vector>' cannot bind to a value of unrelated type 'vector, allocator>>'
and it points to line
func(arg, n, typeval);
Inside this function:
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
You are using const_iterators rather than iterators to perform insertions and removals. You should change the definition of that function as follows:
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
{
for(int i=0; i!=n; ++i) {
T gen = random_gen(valtype);
typename SequenceContainer::iterator it;
// ^^^^^^^^
it=find_if(seq.begin(), seq.end(), std::bind2nd(GreaterThan<T>(), gen));
seq.insert(it, gen);
}
for(int i=n-1; i >=0; i--)
{
int gen = i;
if(i > 0)
gen = random_gen(i)%i;
typename SequenceContainer::iterator it=seq.begin();
// ^^^^^^^^
for(int j = 0; j < gen; j++)
it++;
seq.erase(it);
}
}
Also, you forgot to #include the <cstring> standard header, which contains the definition for the strcmp() function. You are using that function inside your Greater() function:
bool Greater(const string& v1, const string& v2)
{
return strcmp(v1.c_str(), v2.c_str()) > 0;
// ^^^^^^
// You need to #include <cstring> before calling this function
}
Moreover, you're invoking function times() with the wrong arguments (sv and stemp):
//This one desn't work and I'm not sure of the right sytax
times(build_cont<std::vector<Record>,Record>, rsv, n, rstemp);
// ^^^ ^^^^^^