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());
} );
Related
I have this following function to test out thrust but it doesn't compile. It appears my predicate is not valid and my knowledge of C/C++ is not strong enough to know what I need to do correct the compilation issue. Please could someone explain what's going on here and how I can fix it.
void filter(device_vector<int>& x,
device_vector<int>& y,
thrust::unary_function<int,bool> f) {
thrust::copy_if(x.begin(), x.end(), y.end(), f);
}
nvcc -o test test.cu -O2
/usr/lib/nvidia-cuda-toolkit/include/thrust/detail/internal_functional.h(102): error: call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type
detected during:
instantiation of "__nv_bool thrust::detail::predicate_to_integral<Predicate, IntegralType>::operator()(const T &) [with Predicate=thrust::unary_function<__nv_bool, int>, IntegralType=std::ptrdiff_t, T=int]"
/usr/lib/nvidia-cuda-toolkit/include/thrust/detail/function.h(187): here
instantiation of "Result thrust::detail::host_device_function<Function, Result>::operator()(const Argument &) const [with Function=thrust::detail::predicate_to_integral<thrust::unary_function<__nv_bool, int>, std::ptrdiff_t>, Result=std::ptrdiff_t, Argument=thrust::device_reference<int>]"
/usr/lib/nvidia-cuda-toolkit/include/thrust/iterator/transform_iterator.h(306): here
instantiation of "thrust::detail::transform_iterator_base<AdaptableUnaryFunction, Iterator, Reference, Value>::type::reference thrust::transform_iterator<AdaptableUnaryFunction, Iterator, Reference, Value>::dereference() const [with AdaptableUnaryFunction=thrust::detail::predicate_to_integral<thrust::unary_function<__nv_bool, int>, std::ptrdiff_t>, Iterator=thrust::detail::normal_iterator<thrust::device_ptr<int>>, Reference=std::ptrdiff_t, Value=thrust::use_default]"
/usr/lib/nvidia-cuda-toolkit/include/thrust/iterator/iterator_facade.h(128): here
instantiation of "Facade::reference thrust::iterator_core_access::dereference(const Facade &) [with Facade=thrust::transform_iterator<thrust::detail::predicate_to_integral<thrust::unary_function<__nv_bool, int>, std::ptrdiff_t>, thrust::detail::normal_iterator<thrust::device_ptr<int>>, std::ptrdiff_t, thrust::use_default>]"
/usr/lib/nvidia-cuda-toolkit/include/thrust/iterator/iterator_facade.h(305): here
Let's look at some reference first:
The function object pred shall not apply any non-constant function
through the dereferenced iterator. This function object may be a
pointer to function or an object of a type with an appropriate
function call operator.
From "Predicate".
Thus, you shouldn't limit the choices of the caller to unary_function. In a case like this, any object, function, whatever that can be used in the context of copy_if should be allowed to pass. Actually, in vanilla C++ unary_function is deprecated (in favor of std::function, which shouldn't be used here anyway for exactly the same reasons).
I have the following code (as much simplified as possible):
#include <vector>
#include <algorithm>
using std::vector;
enum class Foo {
BAR, BAZ
};
void print_to_file(const vector<const vector<Foo> >& sequences) {
std::for_each(sequences.begin(), sequences.end(), [](const vector<Foo>& sequence) {
});
}
int main(int argc, char **argv) {
return EXIT_SUCCESS;
}
when compiling with g++ (SUSE Linux) 4.7.1 20120723 [gcc-4_7-branch revision 189773] as g++ --std=c++11 test.cpp I get the following error message:
In file included from /usr/include/c++/4.7/x86_64-suse-linux/bits/c++allocator.h:34:0,
from /usr/include/c++/4.7/bits/allocator.h:48,
from /usr/include/c++/4.7/vector:62,
from test.cpp:1:
/usr/include/c++/4.7/ext/new_allocator.h: In instantiation of ‘struct __gnu_cxx::new_allocator<const std::vector<Foo> >’:
/usr/include/c++/4.7/bits/allocator.h:89:11: required from ‘class std::allocator<const std::vector<Foo> >’
/usr/include/c++/4.7/bits/alloc_traits.h:89:43: required from ‘struct std::allocator_traits<std::allocator<const std::vector<Foo> > >’
/usr/include/c++/4.7/ext/alloc_traits.h:109:10: required from ‘struct __gnu_cxx::__alloc_traits<std::allocator<const std::vector<Foo> > >’
/usr/include/c++/4.7/bits/stl_vector.h:76:28: required from ‘struct std::_Vector_base<const std::vector<Foo>, std::allocator<const std::vector<Foo> > >’
/usr/include/c++/4.7/bits/stl_vector.h:208:11: required from ‘class std::vector<const std::vector<Foo> >’
test.cpp:11:25: required from here
/usr/include/c++/4.7/ext/new_allocator.h:83:7: error: ‘const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = const std::vector<Foo>; __gnu_cxx::new_allocator<_Tp>::const_pointer = const std::vector<Foo>*; __gnu_cxx::new_allocator<_Tp>::const_reference = const std::vector<Foo>&]’ cannot be overloaded
/usr/include/c++/4.7/ext/new_allocator.h:79:7: error: with ‘_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = const std::vector<Foo>; __gnu_cxx::new_allocator<_Tp>::pointer = const std::vector<Foo>*; __gnu_cxx::new_allocator<_Tp>::reference = const std::vector<Foo>&]’
the same code compiles fine with VS2012, but fails badly under g++ and I've not the slightest idea how to interpret the error message.
I'm surprised you don't get problems elsewhere, as this vector<const vector<Foo> > is not a possible data type.
The value_type of a std::vector must at minimum be copy constructible (C++03) or movable (C++11). If it is const, you cannot assign or move it.
The Allocator requirements used for standard containers doesn't allow for const objects to be held by the containers. C++11 17.6.3.5 "Allocator requirements" outlines the requirements for standard allocators using a set of tables which start with Table 27. In Table 27, the first definition is for the 'descriptive variables' T, U, and C which are defined as "any non-const, non-reference object type". The descriptive variables X and Y, used for the Allocator class defintions, are:
X - an Allocator class for type T
Y - the corresponding Allocator class for type U
In summary, standard Allocators are defined in terms of parameterization by non-const types.
There's an old GCC/libstdc++ bug for this (resolved as invalid) going back to 2004 (C++2003 has a similar limitation against storing const objects in containers, but it's simpler to show because the 2003 standard more straightforwardly says that the types of objects stored in containers must be 'Assignable').
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16875
What's the difference between the following two cases?
std::pair<int,std::string> example_1 (std::make_pair (1,"foo"));
int value_1 = boost::bind (&std::pair<int,std::string>::first,_1) (example_1);
std::map<int,std::string>::value_type example_2 (std::make_pair (2,"boo"));
int value_2 = boost::bind (&std::pair<int,std::string>::first,_1) (example_2);
The first example works fine but the second does not compile when the binding is done. I have looked at the file stl_map.h and value_type is defined as follows:
typedef std::pair<const _Key, _Tp> value_type;
I don't see the difference. I would appreciate is someone can tell let me know and the reason why the second example does not compile.
The compilation error message is:
.../include/boost/bind/mem_fn.hpp:333:36: error: no matching function for call to ‘get_pointer(const std::pair<const int, std::basic_string<char> >&)’
make: *** [main.o] Error 1
Thanks in advance!
The difference is the use of const in the map value type. std::pair<int,std::string>::first is not an accessible item on std::pair<const int,std::string>::first. Yes, there's an implicit conversion defined by pair from the const version to the non-const version, but that conversion isn't considered for the purposes of calling a member function like this. Those uses of pair might look similar, but really they are completely independent classes that are unrelated to each other in terms of where field locations and such might go.
In essence, you'e asked boost to build code like
std::pair<const int,std::string> example(3, "Hello");
example.std::pair<int,std::string>::first
which is not valid.
map's value_type has a const key (const int in your case), whereas the pair you're using doesn't (plain int in your case).
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.
why is it so useful to make a function const if you only can read variables but not write(class variable)?
If you pass something else a const pointer or const reference to an instance of your class then it can only call the class's const methods (if any).
Obviously, if you never bother with const-correctness with your types then you can ignore this.
I suppose it may also help the compiler optimize things in certain situations, although I am doubtful and, even if it did help, allowing that small improvement (if any) to dictate how you wrote your code would be a case of premature optimization in most situations.
So that you do not "accidentally" modify one of the class variables. It is just a safety measure.
(If you use the const keyword after a function that does modify any data member of the class - either directly or through another function call - you will get a compilation error).
One reason is that const is a virus. That means that if part of the code is const-correct, then the rest of the code won't interoperate with that part.
If you ignore const-correctness, chances of your classes working hand-in-hand with other libraries (beginning with the standard library) are slim.
For example:
#include <vector>
#include <algorithm>
struct X
{
int n;
bool operator< (X b)
{
return n < b.n;
}
};
int main()
{
std::vector<X> vec;
std::sort(vec.begin(), vec.end());
}
With codepad.org
In function 'const _Tp& std::__median(const _Tp&, const _Tp&, const _Tp&) [with _Tp = X]':
/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2642: instantiated from 'void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size) [with _RandomAccessIterator = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<X*, __gnu_norm::vector<X, std::allocator<X> > >, __gnu_debug_def::vector<X, std::allocator<X> > >, _Size = int]'
/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2713: instantiated from 'void std::sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<X*, __gnu_norm::vector<X, std::allocator<X> > >, __gnu_debug_def::vector<X, std::allocator<X> > >]'
t.cpp:17: instantiated from here
Line 90: error: no match for 'operator<' in '__a < __b'
A stdlib compatible comparison operator must make a promise that arguments are not modified. If objects actually were to change while they are compared, an attempt to sort them would be rather futile.
Another example: you won't be able to pass arguments by const reference which is the conventional way of passing large objects. Instead you'd have to pass arguments by modifiable references. Now you won't be able to pass temporaries of any kind to your functions.
If you have a const object, it only allows const member functions to operate on it.
The more of the contract between caller and callee you can express in code instead of documentation, the more help the compiler can give you with complying with that contract (from both ends). const-ness of the implicit this pointer is an important part of that as is const-ness of all other parameter referents. (of course top-level constness of pass-by-value parameters is not part of the contract)
The benefit is that you can get the compiler to enforce where state can be modified. For example if you make a class with private data and all its methods, except, say, the constructor, are const, then you have an immutable data type. The benefit of this is not one of performance, but one of semantics.