I want to implement Functional Object in Polymorphism as follows:
#include <algorithm>
#include <iostream>
using namespace std;
struct Compare {
virtual bool operator() (int, int) const = 0;
};
struct Less : public Compare {
bool operator() (int i, int j)
const {
return (i < j);
}
};
struct Greater : public Compare {
bool operator() (int i, int j)
const {
return (i > j);
}
};
void f(const Compare& c) {
int arr[10] = { 4,2,6,7,1,3,5,9,8,0 };
sort(arr, arr + 10, c);
for (int i = 0; i < 10; ++i)
cout << arr[i] << " ";
}
int main()
{
f(Less());
f(Greater());
}
But it has an error message "no instance of overloaded function "sort" matches the argument list"
I think that the abstract class cannot have an instance.
How can I fix it?
std::sort wants to copy the ordering function.
There is a standard class that "wraps" a reference and makes it copyable; std::ref.
#include <memory>
... and then ...
sort(arr, arr + 10, std::ref(c));
std::sort takes the comparator parameter by-value; you can't pass an abstract class like Compare to it. You can pass Less or Greater directly to it.
You can make f template,
template <typename C>
void f(const C& c) {
int arr[10] = { 4,2,6,7,1,3,5,9,8,0 };
sort(arr, arr + 10, c);
for (int i = 0; i < 10; ++i)
cout << arr[i] << " ";
}
then pass Less or Greater to it like:
f(Less());
f(Greater());
LIVE
Related
I have a question about passing the comparison function to sort().
What I want to do is define a sort() function that takes into account for its calculation a member variable of the class that I want to do the sorting in.
Basically, my code looks like this (simplified to only show the relevant parts):
MappingTechnique.h
struct MappingTechnique {
vector<int> usedIndexCount;
};
struct SimpleGreedyMappingTechnique : MappingTechnique {
bool sortByWeights(int index1, int index2);
};
MappingTechnique.m
bool SimpleGreedyMappingTechnique::sortByWeights(int index1, int index2) {
return usedIndexCount[index1] > usedIndexCount[index2];
}
void SimpleGreedyMappingTechnique::processFrame(Frame frame) {
vector<int> payloadIndices = <generate the vector>
// sort the payload indices according to their current usedIndexCount
sort(payloadIndices.begin(), payloadIndices.end(), sortByWeights);
}
This code doesn't compile, it gives the following error:
error: reference to non-static member function must be called
and points to sortByWeights.
Is it even possible to use a member function of a class for sorting? If it is, how I can implement this?
It is, but in general I would encourage just using a proper functor or a lambda:
Using a lambda:
std::sort(payloadIndices.begin(), payloadIndices.end(), [this](int a, int b){
return this->sortByWeights(a, b);
});
Alternatively using std::mem_fn:
auto sorter = std::bind(std::mem_fn(SimpleGreedyMappingTechnique::sortByWeights), this);
std::sort(payloadIndices.begin(), payloadIndices.end(), sorter);
Alternatively using a functor:
namespace{
struct indicies_less_than
{
const SimpleGreedyMappingTechnique & mapping_tech;
indicies_less_than(const SimpleGreedyMappingTechnique & mapping_tech)
:mapping_tech(mapping_tech){}
bool operator()(int a, int b)
{
return mapping_tech.sortByWeights(a, b);
}
};
}
std::sort(payloadIndices.begin(), payloadIndices.end(), indicies_less_than(*this));
Note:
if the types being sorted were anything more complicated than an int you would definitely want to pass them by const& to prevent copying
As mentioned by Mgetz, a functor can be used. Example of functor:
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <vector>
#define asize 16
class example{
public:
unsigned int a[asize]; // array
std::vector<size_t> v; // indices to array
example(void)
{
v.resize(asize);
for(size_t i = 0; i < asize; i++){
a[i] = rand()%10;
v[i] = i;
}
}
void displayarray(void)
{
for(size_t i = 0; i < asize; i++)
std::cout << std::setw(3) << a[v[i]];
std::cout << std::endl;
}
class lessthan // lessthan functor for std::sort
{
public:
const example &x;
lessthan(const example &e ) : x(e) { }
bool operator()(const size_t & i0, const size_t & i1)
{
return x.a[i0] < x.a[i1];
}
};
void sortarray(void)
{
std::sort(v.begin(), v.end(), lessthan(*this));
}
};
int main()
{
example x;
x.displayarray();
x.sortarray();
x.displayarray();
return 0;
}
I asked this question on stackoverflow STL passing object
I got to know that we pass objects which in tern call the compare operator in them and compare our values and gives us a result. All good.
Now in this piece of code:
class Compare {
public:
bool operator ()(const int &a, const int &b) { return a < b;}
};
void solve(){
set<int, Compare> s;
vector<int> arr = {1,4,6,3,7,2,8,588,5};
for(int e : arr) s.insert(e);
for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;
}
I get error if I do Compare() which is what I thought must be done(passing an object). Why so? How can we pass Compare?
Also in this piece of code I cannot pass a function like:
bool comp(const int &a, const int &b) { return a < b; }
void solve(){
set<int, comp> s;
vector<int> arr = {1,4,6,3,7,2,8,588,5};
for(int e : arr) s.insert(e);
for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;
}
Which is what I expect. Not passing functions.
Now in this piece of code:
bool comp(const int &a, const int &b) { return a < b; }
void solve(){
vector<int> arr = {1,4,6,3,7,2,8,588,5};
nth_element(arr.begin(), arr.begin()+3, arr.end(), comp);
for(int e : arr) cout << e << " "; cout << endl;
}
I am able to pass a function and there is no error. I mean what is going on? From my perspective, we should just pass objects and they will call their () overloaded operator and compare values but sometimes we are passing functions, sometimes passing objects giving error and sometimes we just pass class name. What is exactly going on in c++
Second template parameter of std::set is a type.
You might use function pointer:
bool comp(const int &a, const int &b) { return a < b; }
std::set<int, bool (*)(const int &, const int &)> s(comp);
In the first code snippet the compiler issues an error because you was using an object Compare() as the type template argument instead of the type Compare.
If you will write for example
#include <iostream>
#include <vector>
#include <set>
using namespace std;
class Compare {
public:
bool operator ()(const int &a, const int &b) const { return a < b;}
};
int main()
{
set<int, Compare> s( ( Compare() ) );
vector<int> arr = {1,4,6,3,7,2,8,588,5};
for(int e : arr) s.insert(e);
for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;
return 0;
}
then the program compiles successfully and its output is
588 8 7 6 5 4 3 2 1
That is as the second type template argument of the class template std::set you need to use the type specifier Compare. But if you want to specify the argument of the constructor you need to use an object of the type of the template argument.
The same problem exists for the second code snippet. You need to write like it is shown in this demonstrative program.
#include <iostream>
#include <vector>
#include <set>
using namespace std;
bool comp(const int &a, const int &b) { return a < b; }
int main()
{
set<int, bool ( * )( const int &, const int & )> s( comp );
vector<int> arr = {1,4,6,3,7,2,8,588,5};
for(int e : arr) s.insert(e);
for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl; return 0;
}
The program output is the same as shown above.
Pay attention to that the class template std::set is declared like
template <class Key, class Compare = less<Key>,
class Allocator = allocator<Key> >
class set;
So if you specified explicitly the second template argument (instead of using by default the function object std::less<Key>) then you need to provide a corresponding object of this type in a constructor of the class template std::set.
operator() must be const. That's the API.
class Compare {
public:
bool operator ()(const int &a, const int &b) const { return a < b; }
}
Currently, I'm creating my own vector class, and I like to create instances of any class via shared pointers. So, is there a way to overload operator[] in order to achieve the following code?
class myVector {
public:
myVector(/*some params*/);
~myVector();
// Some kind of overloading of operator []
// Some other code
private:
// private container array
double* vec;
// Some other code
};
int main ()
{
std::shared_ptr<myVector> sp = std::shared_ptr<myVector>(new myVector(/*some params*/));
double val = sp[1];
return 0;
}
You could declare the [] operator for your myVector class as follows (returning a reference to the element so you have read and write access):
double& operator [] (int i)
{
return vec[i];
}
You can then use this operator on the object pointed to by the shared_ptr by first dereferencing that. Here's a runnable example, where I've added some 'dummy' code to the constructor just to make it do something:
#include <iostream>
#include <memory>
class myVector {
public:
myVector(/*some params*/) {
vec = new double[10];
for (int i = 0; i < 10; ++i) vec[i] = 3 * i;
}
~myVector() {
delete[] vec;
}
double& operator [] (int i) {
return vec[i];
}
private:
double* vec;
};
int main()
{
std::shared_ptr<myVector> sp = std::shared_ptr<myVector>(new myVector(/*some params*/));
double val = (*sp)[6];
std::cout << val << std::endl;
(*sp)[4] = 312;
std::cout << (*sp)[4] << std::endl;
return 0;
}
You can overload the operator for the class the following way
double & operator []( size_t i )
{
return vec[i];
}
and
const double & operator []( size_t i ) const
{
return vec[i];
}
and call it like
std::shared_ptr<myVector> sp = std::shared_ptr<myVector>(new myVector(/*some params*/));
//...
std::cout << ( *sp )[i] << '\n';
I would not do this in real application. But just for demonstration, one possibility to achieve what you want (at least technically) is to derive from std::shared_ptr and there declare the index operator. For ex:
#include <memory>
#include <vector>
using namespace std;
template <class T>
class myshared_ptr;
template <class T >
class myshared_ptr<vector<T>> : public shared_ptr<vector<T>>
{
public:
using elem_type = vector<T>;
using shared_ptr<elem_type>::shared_ptr;
using shared_ptr<elem_type>::operator*;
using shared_ptr<elem_type>::get;
typename elem_type::value_type& operator[](size_t idx)
{
return (*get())[idx];
}
};
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
auto p = myshared_ptr<vector<int>>(new vector<int>{1, 2, 3, 4});
cout << p[2] << endl;
return 0;
}
Live Demo
I have a question about passing the comparison function to sort().
What I want to do is define a sort() function that takes into account for its calculation a member variable of the class that I want to do the sorting in.
Basically, my code looks like this (simplified to only show the relevant parts):
MappingTechnique.h
struct MappingTechnique {
vector<int> usedIndexCount;
};
struct SimpleGreedyMappingTechnique : MappingTechnique {
bool sortByWeights(int index1, int index2);
};
MappingTechnique.m
bool SimpleGreedyMappingTechnique::sortByWeights(int index1, int index2) {
return usedIndexCount[index1] > usedIndexCount[index2];
}
void SimpleGreedyMappingTechnique::processFrame(Frame frame) {
vector<int> payloadIndices = <generate the vector>
// sort the payload indices according to their current usedIndexCount
sort(payloadIndices.begin(), payloadIndices.end(), sortByWeights);
}
This code doesn't compile, it gives the following error:
error: reference to non-static member function must be called
and points to sortByWeights.
Is it even possible to use a member function of a class for sorting? If it is, how I can implement this?
It is, but in general I would encourage just using a proper functor or a lambda:
Using a lambda:
std::sort(payloadIndices.begin(), payloadIndices.end(), [this](int a, int b){
return this->sortByWeights(a, b);
});
Alternatively using std::mem_fn:
auto sorter = std::bind(std::mem_fn(SimpleGreedyMappingTechnique::sortByWeights), this);
std::sort(payloadIndices.begin(), payloadIndices.end(), sorter);
Alternatively using a functor:
namespace{
struct indicies_less_than
{
const SimpleGreedyMappingTechnique & mapping_tech;
indicies_less_than(const SimpleGreedyMappingTechnique & mapping_tech)
:mapping_tech(mapping_tech){}
bool operator()(int a, int b)
{
return mapping_tech.sortByWeights(a, b);
}
};
}
std::sort(payloadIndices.begin(), payloadIndices.end(), indicies_less_than(*this));
Note:
if the types being sorted were anything more complicated than an int you would definitely want to pass them by const& to prevent copying
As mentioned by Mgetz, a functor can be used. Example of functor:
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <vector>
#define asize 16
class example{
public:
unsigned int a[asize]; // array
std::vector<size_t> v; // indices to array
example(void)
{
v.resize(asize);
for(size_t i = 0; i < asize; i++){
a[i] = rand()%10;
v[i] = i;
}
}
void displayarray(void)
{
for(size_t i = 0; i < asize; i++)
std::cout << std::setw(3) << a[v[i]];
std::cout << std::endl;
}
class lessthan // lessthan functor for std::sort
{
public:
const example &x;
lessthan(const example &e ) : x(e) { }
bool operator()(const size_t & i0, const size_t & i1)
{
return x.a[i0] < x.a[i1];
}
};
void sortarray(void)
{
std::sort(v.begin(), v.end(), lessthan(*this));
}
};
int main()
{
example x;
x.displayarray();
x.sortarray();
x.displayarray();
return 0;
}
i am trying to create a function that parallelize a for.
I am using the Thread of the SFML and std::bind with template.
Here is what i tried.
#include <SFML/System.hpp>
#include <iostream>
#include <functional>
sf::Mutex mutex;
template <typename F>
void For_Multitread(F Function, std::vector<int>& A);
template <typename F>
void Execute_For(F Function, std::vector<int>& A, int Depart, int Fin);
void Compute(int& Number);
template <typename F>
void For_Multitread(F Function, std::vector<int>& A)
{
for (int Thread = 0; Thread < 2; Thread++)
{
sf::Thread thread(std::bind(&Execute_For, Function, A, Thread * 5, (Thread+1)*5));
thread.launch();
}
mutex.lock();
for (int i = 0; i < 10; ++i)
std::cout << A[i] << std::endl;
mutex.unlock();
}
template <typename F>
void Execute_For(F Function, std::vector<int>& A, int Depart, int Fin)
{
for (int i = Depart; i < Fin; ++i)
{
Function(A[i]);
}
}
void Compute(int& Number)
{
Number++;
}
int main()
{
std::vector<int> A;
for (int i =0; i < 10; i++)
A.push_back(i);
For_Multitread(&Compute, A);
return 0;
}
The error is
no matching function for call to 'bind(<unresolved overloaded function type>, void (*&)(int&), std::vector<int>&, int, int)
Did i miss something really important ?
Execute_For is a function template, therefore you need to either supply it with type template arguments:
std::bind(&Execute_For<F>, Function, A, Thread * 5, (Thread+1)*5)
// ~~~~~~~~~~~~~~^
or use a static_cast:
std::bind(static_cast<void(*)(F,std::vector<int>&,int,int)>(&Execute_For), Function, A, Thread * 5, (Thread+1)*5)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^