typedef std::vector<std::string> TVector;
TVector a_list;
populate vector...
for_each(a_list.begin(),a_list.end(),std::toupper);
error
no matching function for call to 'for_each(std::vector<std::basic_string<char> >::iterator, std::vector<std::basic_string<char> >::iterator, <unresolved overloaded function type>)
Do I need to iterate over the elements using the a standard for loop ? Or is there another way I am not allowed to use c++ 11 features.
Thanks
The toupper function is used for characters, not strings. It also returns the uppercase character, so won't work with for_each, but will with std::transform. There is also the problem that std::toupper exists in two overloads, and the compiler can't decide which one to use. Include <cctype> and use plain toupper (or optionally ::toupper) to get the right function.
You need to iterate first over all strings in the vector, and the iterate again over the string to call toupper.
You can either do it manually, or use transform and use functor objects, something like
struct strtoupper
{
std::string operator()(const std::string& str) const
{
std::string upper;
std::transform(str.begin(), str.end(), std::back_inserter(upper), ::toupper);
return upper;
}
};
// ...
std::transform(a_list.begin(), a_list.end(), a_list.begin(), strtoupper());
You have a vector of std::string and std::toupper expects a char as parameter. So it can not be used. What you can do is:
std::for_each(list.begin(), list.end(),[](std::string& s) { std::for_each(s.begin(), s.end(), std::toupper);});
std::toupper is an overloaded function; that’s why you’re getting <unresolved overloaded function type> in the error message. To select a particular overload, you need to cast it:
static_cast<int(*)(int)>(std::toupper)
for_each is also not the right choice for this task—it will call toupper for each string in the list, then discard the result. std::transform would be the appropriate choice—it writes its output to an output iterator. However, toupper works on characters, not strings. You could still use transform to call toupper for each character in a string:
std::transform(
a_string.begin(),
a_string.end(),
a_string.begin(),
static_cast<int(*)(int)>(std::toupper)
);
It would probably be clearer in this simple case to use loops:
for (TVector::iterator i = a_list.begin(), end = a_list.end(); i != end; ++i) {
for (std::string::size_type j = 0; j < i->size(); ++j) {
(*i)[j] = toupper((*i)[j]);
}
}
But if you wanted to write it with <algorithm> and <iterator> tools only, you could make a functor:
struct string_to_upper {
std::string operator()(const std::string& input) const {
std::string output;
std::transform(
input.begin(),
input.end(),
std::back_inserter(output),
static_cast<int(*)(int)>(std::toupper)
);
return output;
}
};
// ...
std::transform(
a_list.begin(),
a_list.end(),
a_list.begin(),
string_to_upper()
);
Related
Recently, i learnt about the STL types and templates and we were given a challenge as part of practicing the STL and getting used to using it:
Iterate over a std::map<std::string, size_t>
Print its contents
Restrictions:
Can only use: std::vector, std::map, std::string, std::algorithm, std::functional
Cannot define complex types nor templates
Cannot use the . (member access), -> (member access via pointer), * (dereference) operators
Cannot use for, while, do-while nor if-else, switch and other conditionals
Can use std::for_each and other functions of function templates to iterate over collection of elements
No lambdas
No std::cout, std::cerr, std::ostream etc.
No auto types
Can use other STL templates so long as they are included in the headers described at (1)
Allowed to use these functions:
void print(const std::string& str)
{
std::cout << str << std::endl;
}
std::string split(const std::pair<std::string, size_t> &r)
{
std::string name;
std::tie(name, std::ignore) = r;
return name;
}
Originally, i had wanted to use std::for_each(std::begin(mymap), std::end(mymap), print) to iterate over the map and then use the print function to print out the contents. Then i realised that i am actually working with std::pair<std::string, size_t> which made me consider the use of std::bind and std::tie to break the std::pair up. But since i THINK i need to do it inside the std::for_each expression, how can i break up the std::pair while also call print on the elements?
I have also considered using Structured Binding but i am not allowed to use auto.
So, the question is, how do i make use of the STL to iterate the map to extract then print out the keys using the helper functions provided? Obviously, without the restrictions the challenge would have been very easy, but i am at a loss as to what kind of functions in the STL are appropriate in light of this.
I used from your function that takes a "std::pair& as for_each third argument.
I use printf() for print values.
#include <string>
#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
using namespace std;
std::string Split(const std::pair<std::string, size_t> &r)
{
std::string name;
std::tie(name, std::ignore) = r;
return name;
}
int main()
{
string name1{ "John" };
string name2{ "Jack" };
std::map<std::string, size_t> sample = { {name1, 31}, {name2, 35} };
static vector<std::string> names;
std::for_each(sample.begin(), sample.end(), [](std::pair<std::string, size_t> pickup)
{
static int i = 0;
names.push_back(Split(pickup));
printf("%s\n", names[i].c_str());
i++;
});
}
using namespace std;
vector<string> wordDiff(string s, string t)
{
istringstream parse_s(s);
vector<string> words_s(istream_iterator<string>(parse_s), {});
istringstream parse_t(t);
vector<string> words_t(istream_iterator<string>(parse_t), {});
sort(words_s.begin(), words_s.end());
sort(words_t.begin(), words_t.end());
vector<string> funk;
set_difference(words_s.begin(), words_s.end(),
words_t.begin(), words_t.end(),
back_inserter(ret));
return funk;
}
so far i am able to get the array of strings with words in s that are not i t with set_difference however i am unable to get the array in the order of s
The simplest solution is to put all excluded words into a std::unordered_set instead of a std::vector.
Then you can use the set to check each word in your word list if it has to be excluded or not. This way, you no longer need to sort. All you need is a copy_if and a lambda.
Simple solution is not to sort words_s (only words_t) and use std::remove_if:
sort(words_t.begin(), words_t.end());
auto it = std::remove_if( words_s.begin(), words_s.end(), [words_t]( const std::string &str ) {
return std::find( words_t.begin(), words_t.end(), str ) != words_t.end() );
} );
words_s.erase( it, words_s.end() );
you may want consider to use std::unordered_set instead of sorted vector for words_t
vector<string> missingWords(string s, string t) {
//new array to hold s and t
vector<string> arr;
arr.push_back(s);
arr.push_back(t);
//loop through vector
for(auto i=0; i <= arr.size(); i++)
//erase t
arr.erase(remove(arr.begin(), arr.end(), t), arr.end());
return arr;
}
This function just deletes t, but I want to delete t completely so that if there are strings in t that are in s the strings in s will also be deleted.
Based on the name missingWords, I'm going to guess that you want to take each input string, and tokenize it into words. Then you want to create an output that contains all the words present in one that aren't present in the other.
If that's correct, we might consider something like this:
std::vector<std::string> missingWords(std::string const &a, std::string const &b)
{
std::istringstream parse_a(a);
std::vector<std::string> words_a(std::istream_iterator<std::string>(parse_a), {});
std::istringstream parse_b(b);
std::vector<std::string> words_b(std::istream_iterator<std::string>(parse_b), {});
std::sort(words_a.begin(), words_a.end());
std::sort(words_b.begin(), words_b.end());
std::vector<std::string> ret;
std::set_difference(words_a.begin(), words_a.end(),
words_b.begin(), words_b.end(),
std::back_inserter(ret));
return ret;
}
So, we start by breaking each string up into words. Then we sort the words in each vector. Then we find the difference between the two.
Note that as it stands right now, if one string contains two copies of a word, and the other contains only one copy of that word, this will show that word in the list of differences.
One easy way to eliminate that would be to use an std::set instead of an std::vector (and this lets us eliminate the sort as well):
std::vector<std::string> missingWords(std::string const &a, std::string const &b)
{
std::istringstream parse_a(a);
std::set<std::string> words_a(std::istream_iterator<std::string>(parse_a), {});
std::istringstream parse_b(b);
std::set<std::string> words_b(std::istream_iterator<std::string>(parse_b), {});
std::vector<std::string> ret;
std::set_difference(words_a.begin(), words_a.end(),
words_b.begin(), words_b.end(),
std::back_inserter(ret));
return ret;
}
I'm following the book Accelerated C++, and to write a function to split a string into a vector of words (separated by space characters), find_if is utilized.
vector<string> split(const string& str) {
typedef string::const_iterator iter;
vector<string> ret;
iter i = str.begin();
while (i != str.end()) {
i = find_if(i, str.end(), not_space);
iter j = find_if(i, str.end(), space);
if (i != str.end())
ret.push_back(string(i, j));
i = j;
}
return ret;
}
and the definitions of space and not_space:
bool space(char c) {
return isspace(c);
}
bool not_space(char c) {
return !isspace(c);
}
Is it necessary to write two separate predicates here, or could one simply pass !space in place of not_space?
Just use std::not1(std::ptr_fun(space)). std::not1 is declared in <functional>.
(There is also a std::not2 for use with binary predicates; std::not1 is for unary predicates.)
You cannot simply use !space instead of not_space because all you'll be doing in that case is passing false to find_if. That happens because space will decay to a pointer to function, and function pointers are implicitly convertible to bool. Applying ! to the boolean value will always result in false (because the function pointer is never going to be nullptr).
You can reuse the function space by wrapping it in std::not1, which will negate the result of the predicate passed to it. Unfortunately, it's not as simple as writing std::not1(space), because not1 requires that the predicate define a nested type named argument_type, which your predicate doesn't satisfy.
To convert your function into a predicate usable with not1, you must first wrap it in std::ptr_fun. So the line in your split function becomes:
i = find_if(i, str.end(), std::not1(std::ptr_fun(space)));
With C++11, there's no need for the not1 and ptr_fun shenanigans, just use a lambda expression:
i = find_if(i, str.end(), [](char c) {return !space(c);});
You can also declare
template <bool find_space> bool space(char c) {
return find_space ^ (!isspace(c));
}
and then refer to it as space<true> and space<false> in the argument to find_if(). Much more versatile than std::not1().
The signature of transform is:
OutputIterator transform (InputIterator first1, InputIterator last1,
OutputIterator result, UnaryOperation op);
And I want to create a generic token replacing functor, msg_parser, below, so I can use any container (string used in example below) and pass begin and end of container to transform. Thats the idea.
But I can't get this to compile.
Here is my code. Any help would be much appreciated.
#include <iostream>
#include <iterator>
#include <string>
#include <map>
#include <algorithm>
class msg_parser {
public:
msg_parser(const std::map<std::string, std::string>& mapping, const char token = '$')
: map_(mapping), token_(token) {}
// I can use a generic istream type interface to handle the parsing.
std::ostream_iterator operator() (std::istream_iterator in) {
//body will go through input and when get to end of input return output
}
private:
const char token_;
const std::map<std::string, std::string>& map_;
};
int main(int argc, char* argv[]) {
std::map<std::string, std::string> mapping;
mapping["author"] = "Winston Churchill";
std::string str_test("I am $(author)");
std::string str_out;
std::transform(str_test.begin(), str_test.end(), str_out.begin(), msg_parser(mapping));
return 0;
}
Since std::string is a collection of chars, std::transform will iterate over chars exactly distance(first1, last1) times, so in your case it's not possible to change the size of the string. You may be able to transform "$(author)" into another string exactly the same size, though, but I guess it's not what you want.
You probably want to iterate over stream iterators instead of chars:
std::stringstream istrstr(str_test);
std::stringstream ostrstr;
std::transform(std::istream_iterator<std::string>(istrstr),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(ostrstr, " "), // note the delimiter
msg_parser(mapping));
std::cout << ostrstr.str() << std::endl;
By the way, your UnaryOperation works on the iterated type, not on iterators, so operator() should be:
std::string operator() (std::string in) { // ...
You should read the documentations and examples for std::transform in a reference like this.
You'll notice that the operation shall take an element of the input container and generate an element for the output container. Since your containers are strings and the elements are chars, the signature should be char operator()(char). Container-iterators would be wrong in this case. Anyways, the iterators of std::string are char*s, so your std::ostream_iterator are completely senseless.
Having said that, you will notice that transform works on single characters, if you apply it to your string, not on the whole "author" substring. What you are trying to do is best achieved with C++11's std::regex regular expression library, not with std::transform