I want to pass multiple compare functions to the selection sort function as shown below but i get the fallowing error :
Error 1 error C2664: 'sort' : cannot convert parameter 3 from 'bool (__cdecl *)(int,int)' to 'bool *(__cdecl *)(T,T)' c:\users\milad\documents\visual studio 2008\projects\functionpass\functionpass\passcompare.cpp 49 FunctionPass
Code :
bool integerCompare (int a , int b)
{
return(a<b);
}
bool charCompare (char a , char b)
{
return(a<b);
}
bool stringCompare (string a , string b)
{
if(a.compare(b)<0) return true;
else return false;
}
template <class T>
void sort(T x[], int n , bool(*whichCompare(T,T))) // n=size of the array
{
for (int pass=0; pass<n-1; pass++) {
int potentialSmallest = pass;
for (int i=pass+1; i<n; i++) {
if ((*whichCompare)(x[i],x[potentialSmallest])) {
potentialSmallest = i;
}
}
int temp = x[pass];
x[pass] = x[potentialSmallest];
x[potentialSmallest] = temp;
}
}
template <typename T>
void printArray(T a[], int size)
{
for(int i=0;i<size;i++)
cout<<" "<<a[i];
}
int main()
{
int intArray[] = {1,7,-8,-14,46,33,4};
sort <int>(intArray , 7 , integerCompare);
printArray<int>(intArray,7);
}
You have this:
template <class T> void sort(T x[], int n , bool(*whichCompare(T,T)))
{ /*...*/ }
The parameter declaration for a pointer to a function returning a bool and two arguments of type T is wrong. You probably really wanted:
template <class T> void sort(T x[], int n , bool (*whichCompare)(T,T))
{ /*...*/ }
Although typically functions like these are written like this:
template <class T, typename Functor>
void sort(T x[], int n , Functor whichCompare)
{
// ...
bool result = whichCompare(x[i], x[potentialSmallest]);
// ...
}
This way, users can not only pass in function pointers, but function objects that provides an operator()():
struct MyIntegerCompareFunctor
{
bool operator()(int a, int b) { return a < b; }
};
sort(intArray, 7, MyIntegerCompareFunctor());
sort(intArray, 7, &integerCompare); // Works too
Some of the algorithms provided by the C++ standard libraries are written like this.
See my corrections in the lines that have whichCompare in them.
template <class T>
void sort(T x[], int n , bool(*whichCompare)(T,T)) // n=size of the array
{
for (int pass=0; pass<n-1; pass++) {
int potentialSmallest = pass;
for (int i=pass+1; i<n; i++) {
if (whichCompare(x[i],x[potentialSmallest])) {
potentialSmallest = i;
}
}
int temp = x[pass];
x[pass] = x[potentialSmallest];
x[potentialSmallest] = temp;
}
}
You could also templatise the function itself thus:
template< typename T, typename Pred >
void sort( T x[], int n, Pred whichCompare )
{ // etc.
}
I used to do this initially just because it was easier but also allows functors / boost-function/boost-bind etc. to be used with your algorithm.
there is a much more sexy solution:
bool integerCompare (int a , int b)
{
return(a<b);
}
bool charCompare (char a , char b)
{
return(a<b);
}
bool stringCompare (string a , string b)
{
return (a.compare(b)<0);
}
template <typename T, size_t n >
void sort(T (&x)[n], bool whichCompare (T,T) ) // n=size of the array
{
for (int pass=0; pass<n-1; pass++) {
int potentialSmallest = pass;
for (int i=pass+1; i<n; i++) {
if (whichCompare(x[i],x[potentialSmallest])) {
potentialSmallest = i;
}
}
std::swap(x[pass], x[potentialSmallest]);
}
}
template <typename T, size_t n>
void printArray(T (&a)[n])
{
for(int i=0;i<n;i++)
cout<<" "<<a[i];
}
int main()
{
int intArray[] = {1,7,-8,-14,46,33,4};
sort (intArray, integerCompare);
printArray(intArray);
}
Related
For example, I want to display value of only one member of structure/union array, so I want to pass it as argument into a function that will display only that one member and will also display any other single member that I pass as argument.
#include <iostream>
using namespace std;
union ThreeTypes
{
char letter;
int whole;
double real;
};
void showArr(ThreeTypes[], int); // ?? What parameters to pass?
int main()
{
const int SIZE = 50;
ThreeTypes arr[SIZE];
for (int i = 0; i < SIZE; i++)
arr[i].real = 2.37;
showArr(arr, SIZE, ??? ); // what argument to pass to display member?
return 0;
}
void showArr(ThreeTypes arr[],int size,???) // also, what parameters??
{
for (int i = 0; i < size; i++)
cout << arr[i].?? << endl; // member from argument????
}
One option would be a templated pointer-to-member type. These are usually used with class or struct types, but are also valid with a union type. A pointer-to-member type is declared like MemberType ClassType::*pointer_name, and the name of such a pointer can be used to the right of the .* or ->* operator.
template <typename T>
void showArr(const ThreeTypes arr[], int size, T ThreeTypes::*ptr)
{
for (int i = 0; i < size; ++i)
std::cout << (arr[i].*ptr) << std::endl;
}
And you create a pointer-to-member value with the syntax &ClassType::member_name:
int main()
{
const int SIZE = 50;
ThreeTypes arr[SIZE];
for (int i = 0; i < SIZE; i++)
arr[i].real = 2.37;
showArr(arr, SIZE, &ThreeTypes::real);
}
Another more general option would be to take a callable functor:
template <typename F>
void showArr(const ThreeTypes arr[], int size, const F& func)
{
for (int i = 0; i < size; ++i)
std::cout << func(arr[i]) << std::endl;
}
You can create a functor to access a member using a lambda or std::mem_fn:
void print_reals_twice(const ThreeTypes arr[], int size)
{
showArr(arr, size, [](const ThreeTypes& u) { return u.real; });
// Same effects:
showArr(arr, size, std::mem_fn(&ThreeTypes::real));
}
But defining showArr this way also lets you pass a functor that does something more complicated than just return a member, if you wanted:
void print_sin2x_all(const ThreeTypes arr[], int size)
{
showArr(arr, size, [](const ThreeTypes& u) { return std::sin(2*u.real); });
}
In C++17 you should use std::variant:
using ThreeTypes = std::variant<char, int, double>;
template <std::size_t N>
auto show_arr(std::array<ThreeTypes, N>& arr)
{
for (auto& e : arr)
{
std::visit([](auto e) { std::cout << e << std::endl;}, e);
}
}
auto test()
{
std::array<ThreeTypes, 2> arr = {3.4, 'a'};
show_arr(arr);
}
So it seems like C++ doesn't like it when it has to deal with several conversions at once (or more probably I don't know how to do it).
Here are my constructors (each T are different templates, one per class):
Number();
Number(long long int x);
Fraction(T num = T(0), T denom = T(1)) : m_num(num), m_denom(denom) { format(); }
Polynom(T x = T(0)) : m_size(1) { m_vect.push_back(T(x)); }
Matrix(int const& m, int const& n = 0, T const& x = T(0)) : m_m(m), m_n(n) { /*blablabla*/ }
And I am aksing for that :
Matrix<Polynom<Fraction<Number> > > M(5, 5);
I expected that it could be converted step by step as I have written T(...) everywhere, but it doesn't. How to solve that problem?
EDIT:
template <typename T>
class Matrix {
public:
Matrix(int const& m, int const& n = 0, T const& x = T(0)) : m_m(m), m_n(n) {
if (m_n == 0)
m_n = m_m;
T X(0);
m_grid = new T*[m_m];
for (int i = 0; i < m_m; i++) {
m_grid[i] = new T[m_n];
for (int j = 0; j < m_n; j++) {
X = new T(x);
m_grid[i][j] = X;
}
}
}
/* ... */
private:
T** m_grid;
int m_m, m_n;
}
template <typename T>
class Polynom {
public:
//Polynom() : m_size(0) {}
Polynom(T x = T(0)) : m_size(1) { m_vect.push_back(T(x)); }
/* ... */
private:
std::vector<T> m_vect;
int m_size;
}
template <typename T>
class Fraction {
public:
Fraction(T num = T(0), T denom = T(1)) : m_num(num), m_denom(denom) { format(); }
/* ... */
private:
T m_num;
T m_denom;
}
class Number {
public:
Number(long long int x){
if(x == 0)
m_digits.push_back(0);
while (x != 0) {
m_digits.push_back(x % 10);
x /= 10;
}
m_neg = (x < 0);
/* ... */
private:
std::vector<int> m_digits;
bool m_neg;
}
You need to have a Matrix constructor that can take the types (it could be that all it does is forwarding those arguments, but it has to take them).
template<typename T>
struct Matrix
{
template<typename ... Args>
Matrix(Args && ... args)
: mem(std::forward<Args>(args)...)
{ }
T mem;
};
I am facing a problem running this on NetBeans.
Here is my class for a Bubble Sorting algorithm including the main function:
#include <iostream>
using namespace std;
template <class elemType>
class arrayListType
{
public:
void BubbleSort();
private:
elemType list[100];
int length;
void swap(int first, int second);
void BubbleUp(int startIndex, int endIndex);
void print();
void insert();
};
template <class elemType>
void arrayListType<elemType>::BubbleUp(int startIndex, int endIndex)
{
for (int index = startIndex; index < endIndex ; index++){
if(list[index] > list[index+1])
swap(index,index+1);
}
}
template <class elemType>
void arrayListType<elemType>::swap(int first, int second)
{
elemType temp;
temp = list[first];
list[first] = list[second];
list[second] = temp;
}
template <class elemType>
void arrayListType<elemType>::insert()
{
cout<<"please type in the length: ";
cin>>length;
cout<<"please enter "<<length<<" numbers"<< endl;
for(int i=0; i<length; i++)
{
cin>>list[i];
}
}
template <class elemType>
void arrayListType<elemType>::print()
{
cout<<"the sorted numbers" << endl;
for(int i = 0; i<length; i++)
{
cout<<list[i]<<endl;
}
}
The error is represented in this function declaration:
template <class elemType>
void arrayListType<elemType>::BubbleSort(elemType list[], int numvalues)
{
insert();
int current=0;
numvalues--;
while(current < numvalues)
{
BubbleUp(current,numvalues);
numvalues--;
}
print();
}
the main function:
int main()
{
arrayListType<int> list ;
list.BubbleSort();
}
I did another sorting algorithm before but it worked well. How can I really fix this prototyping match thing ?
The error is here:
template <class elemType>
void arrayListType<elemType>::BubbleSort(elemType list[], int numvalues)
In your class, you wrote a prototype for the method, like this:
void BubbleSort();
This doesn't match:
BubbleSort(elemType list[], int numvalues)
To solve the error, remove the parameters from the actual implementation, or add the parameters to the prototype. Your error is self-explanatory, it is complaining about a prototype not matching a definition.
Let me post my code first:
Set.h
#pragma once
#include <string>
template<class _type> class Set
{
public:
Set();
Set m_add(Set _set1, Set _set2);
void m_addElem(Set *const _set, _type _elem);
void m_deleteElem(Set *const _set, _type _elem);
void m_addArray(_type _arr[], int _size);
Set(Set &_coll);
void operator+(_type _num);
void operator+(_type _elem[]);
Set operator+(Set *const _set);
void operator-(_type _num);
Set & operator=(Set &_set);
void m_display();
int m_check(_type elem);
~Set(void);
private:
_type * m_pelements;
int m_setSize;
};
Set.cpp
#pragma warning( disable : 4996 )
#include "Set.h"
#include <iostream>
#include <string>
template <class _type>
Set<_type>::Set()
{
m_setSize = 0;
}
template <class _type>
Set<_type>::Set(Set<_type> &_coll)
{
m_setSize = _coll.m_setSize;
m_pelements = new _type[_coll.m_setSize];
for (int i = 0;i<m_setSize;i++)
{
m_pelements[i] = _coll.m_pelements[i];
}
}
template <class _type>
Set<_type>::~Set()
{
delete [] m_pelements;
}
template <class _type>
Set<_type> Set<_type>::m_add(Set<_type> _set1, Set<_type> _set2)
{
Set<_type> finalSet;
finalSet = _set1;
for (int i = 0;i<_set2->m_setSize;i++)
{
m_addElem(finalSet, _set2->m_pelements[i]);
}
return finalSet;
}
template <class _type>
void Set<_type>::m_addElem(Set<_type> *const _set, _type _elem)
{
if (_set->m_setSize == 0)
{
_set->m_pelements = new _type[1];
_set->m_pelements[0] = _elem;
_set->m_setSize += 1;
}
else
{
_set->m_setSize += 1;
_type * helpElements = new _type[_set->m_setSize];
std::copy(_set->m_pelements, _set->m_pelements + _set->m_setSize-1, helpElements);
helpElements[_set->m_setSize-1] = _elem;
delete [] _set->m_pelements;
_set->m_pelements = helpElements;
/*
_type * helpElements = new _type[_set->m_setSize];
for (int i = 0;i<_set->m_setSize;i++)
{
helpElements[i] = _set->m_pelements[i];
}
delete _set->m_pelements;
_set->m_setSize += 1;
_set->m_pelements = new _type[_set->m_setSize];
for (int i = 0;i<_set->m_setSize;i++)
{
_set->m_pelements[i] = helpElements[i];
}
_set->m_pelements[_set->m_setSize-1] = _elem;
*/
}
}
template <class _type>
void Set<_type>::m_deleteElem(Set<_type> *const _set, _type _elem)
{
int index = _set->m_check(_elem);
if (index >= 0)
{
int k = 0;
_set->m_setSize -= 1;
_type * temp = new _type[_set->m_setSize];
for (int i = 0;i<_set->m_setSize;i++)
{
if (i == index)
k++;
temp[i] = _set->m_pelements[i+k];
}
delete [] _set->m_pelements;
_set->m_pelements = temp;
}
}
template <class _type>
void Set<_type>::m_addArray(_type _elem[], int size)
{
for (int i = 0;i<size;i++)
{
m_addElem(this,_elem[i]);
}
}
template <class _type>
void Set<_type>::operator+( _type _elem)
{
m_addElem(this,_elem);
}
template <class _type>
Set<_type> Set<_type>::operator+(Set<_type> *const _set)
{
return m_add(this,_set);
}
template <class _type>
void Set<_type>::operator+( _type _elem[])
{
m_addArray(this,_elem);
}
template <class _type>
void Set<_type>::operator-( _type _elem)
{
m_deleteElem(this,_elem);
}
template <class _type>
Set<_type> & Set<_type>::operator=(Set<_type> &_set)
{
if(&_set==this) return *this;
delete [] m_pelements;
m_setSize = _coll.m_setSize;
m_pelements = new _type[_coll.m_setSize];
for (int i = 0;i<m_setSize;i++)
{
m_pelements[i] = _coll.m_pelements[i];
}
}
template <class _type>
void Set<_type>::m_display()
{
for (int i = 0;i<m_setSize;i++)
{
std::cout << m_pelements[i] << " " ;
}
std::cout << std::endl;
}
template <class _type>
int Set<_type>::m_check(_type _elem)
{
for (int i = 0;i<m_setSize;i++)
{
if (m_pelements[i] == _elem)
return i;
}
return -1;
}
Main.cpp
#pragma warning( disable : 4996 )
#include "Set.h"
#include "Set.cpp"
#include <iostream>
int main()
{
Set<std::string> zbior1;
zbior1 + std::string("abc");
zbior1 + std::string("abcd");
zbior1 + std::string("abcdef");
zbior1 + std::string("XD");
zbior1.m_display();
zbior1 - "XD";
zbior1.m_display();
std::string tablica[3] = {"ala", "ma", "kota" };
zbior1.m_addArray(tablica,3);
zbior1.m_display();
Set<std::string> zbior2;
zbior2 + std::string("abDDc");
zbior2 + std::string("abcdDD");
zbior2 + std::string("abcdeDDf");
zbior2 + std::string("XDDD");
zbior2.m_display();
Set<std::string> zbior3;
zbior3 = zbior1 + zbior2; //HERE'S THE PROBLEM
}
Problem appears int the last line of Main.cpp
When arguments of Set operator+ are (Set *const _set) I get error " no operator found which takes a right-hand operand of type 'Set<_type>' (or there is no acceptable conversion)'" and if i remove *const there's different error saying "cannot convert parameter 1 from 'Set<_type> *const ' to 'Set<_type>'"
I have no idea how to repair it.
Your
Set operator+(Set *const _set);
is defined as taking a const pointer (which is for sure what you don't want), but you then pass to it an object instead, and not the address of an object. Pass by reference, like
Set operator+(Set const & _set);
Try reading Operator overloading for a very good introduction to the subject.
This method:
Set operator+(Set *const _set);
should probably look like:
Set operator+(Set const &rhs) const;
if it's going to stay a method. See the link in vsoftco's answer for why it should probably be a free non-friend function instead, implemented in terms of operator+=.
You pasted the same message for both errors, afaics, but at least one is complaining about the attempt to pass zbior2 to a method expecting a pointer.
When I call merge_sort I get a string of errors as such the most readable is:
no matching function call to dynamic_array<int>::dynamic_array()
Does having a base class instantiate a sub class cause that sub-class to re-instantiate the calling base class?
This was my first guess.
// Calling main function
#include "c_dynamic_array.cpp"
int main()
{
dynamic_array<int> d1(20);
d1.order();cout << d1 << endl;
d1.rorder();cout << d1 << endl;
d1.randorder();cout << d1 << endl;
d1.merge_sort();cout << d1 << endl; // This line starts a string of errors
}
// Dynamic Array Class and Merge Inner (merge sort) Class
#include "c_include.cpp"
/*
Dynamic Array
*/
using namespace std;
template <typename> class merge_inner;
template <class T> class dynamic_array
{
protected:
T* array;
public:
int size;
void rorder();
void order();
void randorder();
void print_operator(ostream&)const;
dynamic_array(int sizein)
{
size=sizein;
array=new T[size]();
}
void merge_sort()
{
merge_inner<T> M1;
}
};
template <class T> void dynamic_array<T>::print_operator(ostream &os=cout)const
{
for (int i = 0; i < size; i++) os << array[i] << endl;
}
template <class T> void dynamic_array<T>::randorder()
{
srand(time(NULL));
int *ap;
for(ap=array;ap!=array+size;++ap){*ap=rand()%size;}
}
template <class T> void dynamic_array<T>::order()
{
int *ap,i=0;
for(ap=array;ap!=array+size;++ap)
{
*ap=i;
++i;
}
}
template <class T> void dynamic_array<T>::rorder()
{
int *ap,i=size-1;
for(ap=array;ap!=array+size;++ap)
{
*ap=i;
--i;
}
}
template<class T> ostream& operator<<(ostream& stream, dynamic_array<T> const& data)
{
data.print_operator(stream);
return stream;
}
/*
Merge Sort
*/
template <class T> class merge_inner : public dynamic_array <T>
{
using dynamic_array<T>::array;
private:
const static int size;
T *scratch;
void flip_if_unordered(int &x, int &y)
{
if(array[x]>array[y])
{
int tmp=array[x];
array[x]=array[y];
array[y]=tmp;
}
}
void merge_algo(int &left, int &right_begin, int &right)
{
int iter,iter_left=left,iter_right=right_begin;
for(iter=left;iter<=right;++iter)
{
if( (iter_right>right) || ((iter_left < right_begin) && (array[iter_left]<=array[iter_right])))
{
scratch[iter]=array[iter_left];
++iter_left;
}
else
{
scratch[iter]=array[iter_right];
++iter_right;
}
}
for(iter=left;iter<=right;++iter){array[iter]=scratch[iter];}
}
void merge_recurse(int left,int right)
{
int left_end=(left+((right-left)/2));
int right_begin=left_end+1;
if(((left+1)==right)){flip_if_unordered(left,right);return;}
else if ((left==right)){return;}
else
{
merge_recurse(left,left_end);
merge_recurse(right_begin,right);
merge_algo(left,right_begin,right);
}
}
public:
merge_inner()
{
scratch = new T[size]();
if(scratch != NULL){merge_recurse(0, size);}
}
};
/*Quick Sort
void quick_sort()
{
quick_recurse(0,size);
}
void quick_recurse(int left, int right)
{
int l = left, r = right, tmp;
int pivot = array[(left + right) / 2];
while (l <= r)
{
while (array[l] < pivot)l++;
while (array[r] > pivot)r--;
if (l <= r)
{
tmp = array[l];
array[l] = array[r];
array[r] = tmp;
l++;
r--;
}
}
if (left < r)quick_recurse(left, r);
if (l < right)quick_recurse(l, right);
}
*/
dynamic_array seems to be missing a default constructor, and since it has a custom constructor the compiler will not provide one. Add this to your class:
dynamic_array()
{
size = 0;
array = new T[0](); // or NULL, but note that new T[0] will be != NULL
}
Alternatively, provide a default sizein for your existing constructor so that it can be used as a default constructor as well:
dynamic_array(int sizein = 0)
Since your base class dynamic_array<T> doesn't have a default constructor, every derived class constructor must call some base constructor one way or another. Put the base initialization in the constructor initializer list. For example:
template <typename T>
class merge_inner : public dynamic_array<T>
{
public:
merge_inner() : dynamic_array<T>(0) { }
// ...
};