How do I declare a custom compare function inside a class? - c++

When I define the custom comparison function inside the class I'll get the error:
'Solution::myfunction': non-standard syntax; use '&' to create a pointer to member
But if I define it outside the class it works. How can I define it inside the class?
class Solution {
public:
bool myfunction(const vector<int> &i, const vector<int> &j) {
return i.front() < j.front());
}
vector<vector<int>> vec;
...
sort(vec.rbegin(), vec.rend(), myfunction);
}
Thanks

Non-static member functions take an implicit this as first parameter. The correct way to call your member function would be
Solution s;
std::vector<int> x;
s.myfunction(x,x);
when you actually want a function that only takes two vectors as parameter. Declare it as static or use a free-function (the prefered way).
PS: Unless you need to call the same comparison function in different scopes, I would suggest to use a lambda:
sort(vec.begin(), vec.end(),
[](const vector<int> &i, const vector<int> &j) {
return i.front()<j.front();
}
);

There are couple way to fix it:
I prefer provide lambda:
sort(vec.rbegin(), vec.rend(), [](const auto &a, const auto &b)
{
return std::lexicographical_compare(a.begin(), a.end(),
b.begin(), b.end());
});
Other way is to provide comparetion class:
class CmpIntVectors {
public:
bool operator(const vector<int> &a, const vector<int> &b) const
{
return std::lexicographical_compare(a.begin(), a.end(),
b.begin(), b.end());
}
};
...
sort(vec.rbegin(), vec.rend(), CmpIntVectors{});
Or make myfunction static.
Disclaimer: I'm assuming that your vec looks like this:
std::vector<std::vector<int>> vec;

Lambdas are the preferred way nowadays instead of defining your own comparison function. They are more readable and in-place, i.e. you can see the code where you call sort() rather than look in some header file elsewhere.

If for some reason you still want to use class member function, then use lambda and pass this to it:
sort(vec.rbegin(), vec.rend(), [this](const vector<int> &i, const vector<int> &j){
return this->myfunction(i, j);
});

Related

Reference to a non-static member should be called

class Solution {
public:
bool comp(int &a,int &b){
return a>b;
}
int findKthLargest(vector<int>& nums, int k) {
vector<int> vec= nums;
sort(vec.begin(),vec.end(),comp); //error: reference to non-static member should be called
cout << vec[k-1];
}
};
What is the reason for this error? And how do I fix this?
The problem is that you're passing a member function to std::sort and since it is a member function you need an instance to invoke it on.
You have a few solutions.
Pass a non-member function. This can be just a free function or a static function
Use a lambda.
sort(vec.begin(),vec.end(), [this](int i, int j){return comp(i,j);});
Use std::bind.
sort(vec.begin(), vec.end(), std::bind(&Solution::comp, this, _1, _2));
Use standard library compare function object.
sort(vec.begin(), vec.end(), std::greater<int>());
Use a custom function object
struct {
bool operator()(int a, int b) const
{
return a > b;
}
} comp;
.
.
sort(vec.begin(), vec.end(), comp);
P.S:
As others have already pointed out there's no point of using references in comp and make sure in your findKthLargest function you actually return something.
In C++, sort function requires a static function return bool, but comp is a member of Solution class (bool Solution::comp(int&, int&)).
Easiest way is if you make comp a static function
static bool comp(int &a,int &b){
return a>b;
}
Or you can use std::bind

How should I correct this priority_queue comparison function?

With a number array nums, I'd like to sort the unique numbers by the frequency of their occurrences. The compiler is complaining about passing the unordered_map as 'this' argument discards qualifiers. How do I fix this?
void sortByFreq(const vector<int>& nums) {
unordered_map<int, int> counts;
for (auto i: nums) ++counts[i];
auto byCount = [counts](const int& a, const int& b) { return counts[a] > counts[b]; };
priority_queue<int, vector<int>, decltype(byCount)> minFreq(byCount);
for (auto& kv: counts) {
minFreq.push(kv.first);
}
......
}
Why you there is a priority_queue? Looks like we missing some information.
There are couple ways to fix issue with counts and lambda:
use at instead operator[] - IMO best solution
capture counts by reference
make lambda mutable (I don't like this one)
From what you have described this should do the job:
vector<int> sortedByFreq(const vector<int>& nums)
{
unordered_map<int, int> counts;
for (auto i : nums)
++counts[i];
vector<int> result = nums;
std::sort(result.begin(), result.end(),
[counts](auto a, auto b) {
return counts.at(a) > counts.at(b);
});
return result;
}
You need to make the lambda mutable, to allow the non-const member function to be called on the copy-captured counts. (Note that the operator[] of std::unordered_map is a non-const member function, which will perform insertion if the key does not exist.)
mutable: allows body to modify the parameters captured by copy, and to call their non-const member functions
e.g.
auto byCount = [counts](const int& a, const int& b) mutable { return counts[a] > counts[b]; };
You can use at instead of operator[], as it has a const qualified overload.
auto byCount = [counts](const int& a, const int& b) { return counts.at(a) > counts.at(b); };

Using member variable as predicate

I am trying to find an object in a vector of objects whos value of a member variable is true. Could it be done without defining a lamba function or function object, by just specifying the member variable itself:
class A
{
public:
explicit A(bool v, int v2, float v3) : value(v), value2(v2), value3(v3)
{}
...
bool value;
int value2;
float value2;
...
}
int main()
{
std::vector<A> v;
v.push_back(A(false, 1, 1.0));
v.push_back(A(true, 2, 2.0));
v.push_back(A(false, 3, 3.0));
auto iter = std::find_if(v.begin(), v.end(), &A::value);
}
Compiling as is above does not work as it assumes a A* and not A.
Not that its a problem to use lambdas, just curious.
You may use std::mem_fn
auto iter = std::find_if(v.begin(), v.end(), std::mem_fn(&A::value));
Demo
Note that range library should allow directly:
auto iter = range::find_if(v, &A::value);
If you cannot use C++11 lambdas, you can do that with std::bind:
auto iter = std::find_if(v.begin(), v.end(), std::bind(&A::value, std::placeholders::_1));
A solution could be the following
(Optional) Don't mark your constructor A(bool) as explicit to allow implicit conversion from bool to A (live demo on coliru)
Overload operator==() so that it only uses value to establish equality.
You can also supply an operator==(bool v) { return value == v;} (see this demo)
Of course I would advise you not to use that solution as it is quite dirty. Just supply a predicate using std::find_if to do the job. Note that the said predicate must have an operator() so of course you cannot supply a value such as a bool as the predicate to std::find_if

Sort by a function that takes argument(s) in c++?

I'm trying to write a function to sort a vector of custom class objects by a variety of different attributes.
The c++ sort reference, found here:
http://www.cplusplus.com/reference/algorithm/sort/
Says that you can sort like this:
std::sort (myvector.begin(), myvector.end(), myfunction);
What I would like to be able to do is pass an argument to myfunction in addition to the two objects from my vector like this:
std::sort (myvector.begin(), myvector.end(), myfunction(mode=7));
Do you know of a way to do so?
I am relatively new to c++, coming from python where this would be easy.
If you are using C++11, you can use a lambda:
sort(myvec.begin(), myvec.end(), [] (Type a, Type b) { return myfunction(a,b,7); });
You can use a functor instead of a free function:
struct Functor{
int mode;
bool operator() (int a,int b) { return (a<b);}
} functor;
The overloaded () operator executes when the functor is called by sort. In there you can have a variable mode and use it as you need.
Then set mode (you could also set in on the functor constructor) and call sort using it:
functor.mode = 7; // or set it in the constructor
std::sort (myvector.begin(), myvector.end(), functor);
Create a functor:
struct MyFunction {
bool operator()(const T& lhs, const T& rhs) const { /* implement logic here */ }
int mode;
};
Then pass an instance of that instead of your plain function myfunction. Here, T is the type used to instantiate your std::vector.
MyFunction f;
f.mode = 7;
std::sort (myvector.begin(), myvector.end(), f);
If you have C++11 support, you can use a lambda function:
std::sort(myvector.begin(), myvector.end(), [](const T&a, const T& b) { /* implement*/ });

Object initialization in C++

I am looking at someone's code, I don't understand how the object getting initialized here:
template <typename String>
void test_numbers()
{
SampleClass<String> compare;
String lhs = "abc";
String rhs = "efg";
check_equality(compare(lhs, rhs), true);
}
The object compare is created of class type SampleClass and then assigned 2 strings when passed on as a parameter. How this initialization works? Any comments? suggestions?
//I am initialised with my default constructor (no args)
SampleClass<String> compare;
//I am initialised with my `const char*` constructor (and assignment operator)
String lhs = "abc";
String rhs = "efg";
//Compare (already initialised) is being invoked by it's `operator()`
check_equality(compare(lhs, rhs), true);
compare is already constructed. It has an operator() implemented that allows it to appear as a function, accepting arguments.
you can make your own easily.
struct op_test{
int i;
op_test(int i_) : i(i_){}
int operator()(int j)const { return j*i; }
};
:::
op_test ot(5);
ot(6); //5*6
The reason this is useful is because we can do thing like this.
std::vector<int> a(700); //700 ints
std::transform(a.begin(), a.end(), b.begin(), op_test(5));
//or
std::transform(a.begin(), a.end(), b.begin(), &my_func); //calls a function
std::transform(a.begin(), a.end(), b.begin(), [](int i){ return i*5; }); //lambda
see here:
http://msdn.microsoft.com/en-us/library/5tk49fh2(v=vs.80).aspx
useful with
http://en.cppreference.com/w/cpp/algorithm
It simply creates an automatic variable of type SampleClass<String>. Then its operator() is called with two String arguments.