Custom Compare function for std::binary_search - c++

Is there any problem with this code?
bool Spellcheck::smart_comp(string value, string key){
return true;
}
void func(){
std::string aprox_key = "hello";
if(std::binary_search(this->words.begin(), this->words.end(), aprox_key, smart_comp)){
std::cout << "Found" << std::endl;
}
}
I am trying to write my own compare function for comparing strings in binarysearch
I am getting following error:
xyz.cpp:40:85: error: no matching function for call to ‘binary_search(std::vector<std::basic_string<char> >::iterator, std::vector<std::basic_string<char> >::iterator, std::string&, <unresolved overloaded function type>)’
xyz.cpp:40:85: note: candidates are:
/usr/include/c++/4.6/bits/stl_algo.h:2665:5: note: template<class _FIter, class _Tp> bool std::binary_search(_FIter, _FIter, const _Tp&)
/usr/include/c++/4.6/bits/stl_algo.h:2698:5: note: bool std::binary_search(_FIter, _FIter, const _Tp&, _Compare) [with _FIter = __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >, _Tp = std::basic_string<char>, _Compare = bool (Spellcheck::*)(std::basic_string<char>, std::basic_string<char>)]
/usr/include/c++/4.6/bits/stl_algo.h:2698:5: note: no known conversion for argument 4 from ‘<unresolved overloaded function type>’ to ‘bool (Spellcheck::*)(std::basic_string<char>, std::basic_string<char>)’
Any help is appreciated...

Is there any problem with this code?
bool Spellcheck::smart_comp(string const value, string const key){
return true;
}
Other than it always returns true? Yes, the basic problem is that a member function has an implicit parameter this, so the signature does not match that of the expected predicate. You should be doing this function static or even a free function (friended if needed). Also you are copying the strings each time, it would be best if you take the arguments by const reference to avoid unneeded copies.
In case the real result of the predicate depends on the state of the Spellcheck object, you will have to bind that state to the member function in order to create a function object with the appropiate signature:
std::binary_search(
this->words.begin(), this->words.end()
, std::bind( &Spellcheck::smart_comp, this )
);

You're trying to pass a non-static member function, which is not convertible to the required binary function (on account of having three actual parameters).
Try declaring your smart_comp function static. (Of course then you can't refer to instance members; if you need statefulness, you'll have to write a full functor.)

Assuming this->words's type is std::vector<std::string> and func is a member of Spellcheck, you can work it around declaring smart_comp to be static. But I would think twice on your class design.

Related

QVector<QVector int> > modify "inside" vector

I have the following variable in QT:
QVector<QVector <int> > buff_d1;
and I need to modify the "inner" vector:
buff_d1.at(i).removeFirst();
buff_d1.at(i).push_back(d1.at(i).at(sample_number));
this is causing the errors:
passing 'const QVector<int>' as 'this' argument of 'void QVector<T>::removeFirst() [with T = int]' discards qualifiers [-fpermissive] buff_d2.at(i).removeFirst();
passing 'const QVector<int>' as 'this' argument of 'void QVector<T>::push_back(const T&) [with T = int]' discards qualifiers [-fpermissive] buff_d1.at(i).push_back(d1.at(i).at(sample_number));
I understand that the "inner" vector is const so I can't modify it, but what is the work around it?
Your at() function returns a const reference:
const T & QVector::at(int i) const
and you're trying to modify this with the removeFirst() function. You should rather use the [] operator to modify it since it provides a non-const returning overload:
T & QVector::operator[](int i)
The same applies for the second error.
at(int index) member function returns an const reference, see the documentation here, so you need to use operator[int index] to return a non const reference to be able to modify it.

partial_sort and smart pointers

I have a SetPartitionVector class which is derived from vector<SetPartition>. I'd like to partial_sort this vector using a custom comparison function but I have an error at compilation.
bool ScalableSummary::featuresDistComp(SetPartition cluster1, SetPartition cluster2){
return (segmentClusters.AverageSOD(cluster1) > segmentClusters.AverageSOD(cluster2));
}
void ScalableSummary::selectLeastConsensualFeatures(const int p){
partial_sort(segmentClusters.begin(), segmentClusters.begin() + p, segmentClusters.end(), featuresDistComp);
}
segmentClusters is a member of ScalableSummary of type SetPartitionVector which was filled this way :
SetPartition_ptr cluster;
...
segmentClusters.push_back(*cluster);
SetPartition_ptr is a smart pointer defined like this :
typedef boost::shared_ptr<SetPartition> SetPartition_ptr;
This is the error I get from the compiler :
g++ -o ScalableSummary.o -c ScalableSummary.cpp -Iinclude -Wall -g
ScalableSummary.cpp: In member function ‘void ScalableSummary::selectLeastConsensualFeatures(int)’:
ScalableSummary.cpp:56:108: erreur: no matching function for call to ‘partial_sort(std::vector<SetPartition>::iterator, __gnu_cxx::__normal_iterator<SetPartition*, std::vector<SetPartition> >, std::vector<SetPartition>::iterator, <unresolved overloaded function type>)’
ScalableSummary.cpp:56:108: note: candidates are:
/usr/include/c++/4.6/bits/stl_algo.h:5240:5: note: template<class _RAIter> void std::partial_sort(_RAIter, _RAIter, _RAIter)
/usr/include/c++/4.6/bits/stl_algo.h:5279:5: note: void std::partial_sort(_RAIter, _RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<SetPartition*, std::vector<SetPartition> >, _Compare = bool (ScalableSummary::*)(SetPartition, SetPartition)]
/usr/include/c++/4.6/bits/stl_algo.h:5279:5: note: no known conversion for argument 4 from ‘<unresolved overloaded function type>’ to ‘bool (ScalableSummary::*)(SetPartition, SetPartition)’
The function object you pass to std::partial_sort needs to be either a callable object, or a function pointer. To make a function pointer you nedd to use the address-of operator &, just like when you make a pointer out of any other variable:
partial_sort(..., &featuresDistComp);
// ^
// |
// Note address-of operator here
Also, I hope your function is marked as static? You can't use non-static member functions as ordinary function pointers. The reason is that all non-static member functions have a hidden first arguments that is the this pointer inside the function. So either make sure the function is static or use e.g. std::bind:
using namespace std::placeholders; // for _1, _2, _3...
partial_sort(..., std::bind(&ScalableSummary::featuresDistComp, this, _1, _2));

How to curry using standard functors

I have the following loop:
MyList li;
vector<Token*>::iterator itr = tokens.begin();
for (; itr != tokens.end(); ++itr) {
li.add_string((*itr)->get_name());
}
I am thinking if I can use functor to replace this loop. One goal here is I could just use standard functor; I do not want to write a separate class just for the purpose of operator().
Here is my version:
for_each(tokens.begin(), tokens.end(),
std::bind1st(std::bind2nd(std::mem_fun(&MyList::add_string),
std::mem_fun(&Token::get_name)),
&li)
);
Unfortunately I get that nasty GCC template compile error.
Can you point me what should be the right functor currying here?
I cannot use c++11.
[EDIT]
My compiler does not support lamda.
Here is the error message if it helps:
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h: In instantiation of 'std::binder1st<std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> > >':
abc.c:823: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:100: error: no type named 'second_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:103: error: no type named 'first_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:106: error: no type named 'first_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:111: error: no type named 'second_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:117: error: no type named 'second_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h: In function 'std::binder1st<_Operation> std::bind1st(const _Operation&, const _Tp&) [with _Operation = std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >, _Tp = MyList*]':
abc.c:823: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:126: error: no type named 'first_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/algorithm:62,
from abc.c:4:
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_algo.h: In function '_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<Token**, std::vector<Token*, std::allocator<Token*> > >, _Funct = std::binder1st<std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> > >]':
abc.c:824: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_algo.h:4200: error: no match for call to '(std::binder1st<std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> > >) (Token*&)'
[EDIT2] I know why I get the error now. bind2nd's implementation is this:
template<typename _Operation, typename _Tp>
inline binder2nd<_Operation>
bind2nd(const _Operation& __fn, const _Tp& __x)
{
typedef typename _Operation::second_argument_type _Arg2_type;
return binder2nd<_Operation>(__fn, _Arg2_type(__x));
}
_Operation is mem_fun_t from MyList::add_string, this is fine because mem_fun_t provides operator() API.
The problem is here: _Arg2_type(__x), because _Arg2_type is _Operation::second_argument_type but mem_fun_t does not have second_argument_type attribute because it is sub-class of unary_function.
Well, if someone could confirming my tracing of type conversion, I'd appreciate it very much.
Thanks Eric, your mentioning "bind1st and bind2d requires the value to be constant" triggers me(but I think your wording is not right per-Se because the key is not the value must be constant, rather the value must be of certain type).
Lastly, GCC extension compose is best solution; I am sure boost has equivalent.
The error comes from the fact you are trying to bind a function as the second parameter for the add_string method of MyList. bind1st and bind2nd requires the value to be constant and are not geared to receive functions as value to bind.
for_each requires a function which takes iterator as first its parameter. What you want to accomplish can't be done without an external function(which is the equivalent of a lambda but not nearly as elegant) if you really insist on using for_each. This function would need to receive the list and token iterator as parameter. You can then bind the list to the function with either bind1st or bind2nd depending on the order in which you declare the parameter.
Let's you have this function:
void AddTokenNameToList(MyList& li, Token* token)
{
li.add_string(token->get_name());
}
You could have this for_each:
for_each(tokens.begin(), tokens.end(), std::bind1st(AddTokenNameToList, li));
If list parameter were inverted, you would use bind2nd instead to bind the list value.
You could argue that this function is custom for this particular case and not as elegant as using only std methods. I guess you could get crazy and template that function to receive method to apply to first parameter and the one for the second but what you really want here is a lambda and since you can't use them, this is as close as you gonna get.
At this point however, you have to wonder if it really saves code. That's one of the reason bind1st and bind2nd have bad rep and considered almost useless. However it lets you use some other nice algorithm so they still have some advantages.
If your compiler supports it, you can use lambdas:
for_each(tokens.begin(), tokens.end(), [&li] (Token * val)
{
li.add_string(val->get_name());
} );

using comparing function

I have this function
std::vector <std::vector <int> > puddles;
std::set <int> is_checked;
size_t M, N;
bool v_compare(int a, int b){
return puddles[(a-a%M)/M][a%M] < puddles[(b-b%M)/M][b%M];
}
and I want to find the set element which corresponds to the minimal value in puddles (I use i*M+j as a key in the set). So I am trying to use my function as a predicate for min_element
close(*std::min_element(is_checked.begin(), is_checked.end(), v_compare));
but I got this error
:113:82: error: no matching function for call to 'min_element(std::set<int>::iterator, std::set<int>::iterator, <unresolved overloaded function type>)'
:113:82: note: candidates are:
/usr/include/c++/4.6/bits/stl_algo.h:6173:5: note: template<class _FIter> _FIter std::min_element(_FIter, _FIter)
/usr/include/c++/4.6/bits/stl_algo.h:6201:5: note: _FIter std::min_element(_FIter, _FIter, _Compare) [with _FIter = std::_Rb_tree_const_iterator<int>, _Compare = bool (TFlood::*)(int, int)]
/usr/include/c++/4.6/bits/stl_algo.h:6201:5: note: no known conversion for argument 3 from '<unresolved overloaded function type>' to 'bool (TFlood::*)(int, int)'
There is a difference between a pointer to function and a pointer to member function. A class member which is not static gets you a pointer to member function. But std::min_element only accepts a pointer to function or other callable type, and a pointer to member function doesn't qualify since it can't be called without a pointer or reference to a class object. And as you found, if you try making the function a static member, then it can't get at the member M. (Maybe puddles too, if that's also a member.)
It looks like you're using g++ 4.6, which supports lambdas. So the easiest solution is:
close(*std::min_element(is_checked.begin(), is_checked.end(),
[this](int a, int b) { return puddles[a/M][a%M] < puddles[b/M][b%M]; }));
(I got rid of the subtractions, since division of integer types always rounds toward zero, so (a-(a%M))/M is always the same result as a/M.) Make sure you use the -std=c++0x compiler flag. The lambda magic takes care of "capturing" the this pointer for later use by the comparison object.

tr1::mem_fn and members with default arguments

I have class with a member function that takes a default argument.
struct Class
{
void member(int n = 0)
{}
};
By means of std::tr1::mem_fn I can invoke it:
Class object;
std::tr1::mem_fn(&Class::member)(object,10);
That said, if I want to invoke the callable member on the object with the default argument, what's the correct syntax?
std::tr1::mem_fn(&Class::member)(object); // This does not work
g++ complains with the following error:
test.cc:17: error: no match for call to ‘(std::tr1::_Mem_fn<void (Class::*)(int)>) (Class&)’
/usr/include/c++/4.3/tr1_impl/functional:551: note: candidates are: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class&, _ArgTypes ...) const [with _Res = void, _Class = Class, _ArgTypes = int]
/usr/include/c++/4.3/tr1_impl/functional:556: note: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class*, _ArgTypes ...) const [with _Res = void, _Class = Class, _ArgTypes = int]
Still, the I have the same problem when Class::member is overloaded by members that takes different arguments...
Default functions are bound at call time, but can't be bound into any sort of wrapper implicitly, because of the way they are implemented. When you pass &Class::member, mem_fn only sees a void (Class::*)(int), and can't see the default argument. Using tr1::bind, you can bind the default argument explictly: std::tr1::bind(&Class::member, 0) or you can use it as you would mem_fn, but you can't do both in one object. You would have to write your own wrapper class for that.
As for overloads, you will have to explicitly specify the template arguments for mem_fn so the right function pointer is picked as in mem_fn<void(int)>(&Class::member).
The reason is that any default arguments do not change the function type of a function.
mem_fn has no way to know the function only requires 1 argument, or that the functions' second argument is optional, since all the knowledge it gets is given to it by the type of &Class::member (which stays void(Class::*)(int)) . It therefor requires an integer as the second argument.
If you want to pass the address of a member function overloaded, you have to cast to the right member function pointer type:
static_cast<void(Class::*)()>(&Class::member) instead of just &Class::member, so the compiler has a context to figure out which address is to be taken.
Edit: coppro has a nicer solution how to provide context: std::tr1::mem_fn<void()>(&Class::member)