std::remove_if and std::isspace - compile-time error - c++

I have the following code:
#include <algorithm>
#include <cctype>
#include <string>
int main()
{
std::string str;
str.erase(std::remove_if(str.begin(), str.end(), std::isspace), str.end());
}
MSVC-11.0 compiles this code without any error, but gcc 4.7.2 gives me the following errors:
main.cpp: In function ‘int main()’:
main.cpp:8:66: error: no matching function for call to ‘remove_if(std::basic_string<char>::iterator, std::basic_string<char>::iterator, <unresolved overloaded function type>)’
main.cpp:8:66: note: candidate is:
In file included from /usr/include/c++/4.7/algorithm:63:0,
from main.cpp:1:
/usr/include/c++/4.7/bits/stl_algo.h:1160:5: note: template<class _FIter, class _Predicate> _FIter std::remove_if(_FIter, _FIter, _Predicate)
/usr/include/c++/4.7/bits/stl_algo.h:1160:5: note: template argument deduction/substitution failed:
main.cpp:8:66: note: couldn't deduce template parameter ‘_Predicate’
I found this question about it, but according to the cppreference, there isn't any version of this function that takes two arguments. I found this question too, but according to the cppreference (yep, again) I see that there's only one std::isspace function overload.
Who's right? What am I doing wrong? How can I fix it?

There is another overload of std::isspace, so you need to specify which one to use. An easy way is to use a lambda (or write your own one-line function if you don't have C++11 support):
std::remove_if(str.begin(), str.end(),
[](char c){
return std::isspace(static_cast<unsigned char>(c));
});

std::isspace is an overloaded function, although the two overloads reside in different headers. Also note that your code may introduce undefined behaviour because only values in the range 0..UCHAR_MAX can be passed to std::isspace, whereas a char is possibly signed.
Here is a solution:
std::string str;
auto f = [](unsigned char const c) { return std::isspace(c); };
str.erase(std::remove_if(str.begin(), str.end(), f), str.end());

The following solution should get you around the compile-time error:
str.erase(std::remove_if(str.begin(), str.end(), (int(*) (int)) std::isspace), str.end());

After C++ 11, you can use lamda function (easier to understand), see below:
string s = " 3/ 2";
auto isSpace = [](const unsigned char c)
{
return std::isspace(c);
};
s.erase(remove_if(s.begin(), s.end(), isSpace), s.end());
Output:
3/2

Related

RCPP - no matching function for call to 'transform'

I have a problem while using Rcpp on Mac (on Windows the problem does not occur).
Here is the C++ Code that causes the error.
#include <Rcpp.h>
using namespace Rcpp;
NumericVector vecpow(const IntegerVector base, const NumericVector exp)
{
NumericVector out(base.size());
std::transform(base.begin(), base.end(), exp.begin(), out.begin(), ::pow);
return out;
}
Seems like nothing too fancy or complicated.
Still I get the following error when I try to compile it:
na_ma.cpp:7:3: error: no matching function for call to 'transform'
std::transform(base.begin(), base.end(), exp.begin(), out.begin(), ::pow);
^~~~~~~~~~~~~~
/Library/Developer/CommandLineTools/usr/include/c++/v1/algorithm:2028:1: note: candidate function template not viable: requires 4 arguments, but 5 were provided
transform(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _UnaryOperation __op)
^
I am wondering how to fix this. While searching for solutions I came to some suggestions to create a Makevars file - but this did not work for me.
Would be also nice, if somebody could explain to me, why this error is occurring since I don't understand it.
This is actually C++ compiler error. Compiler cannot match ::pow with BinaryOp, so pack it into lambda. This works for me
std::transform(base.cbegin(), base.cend(), exp.cbegin(), out.begin(), [](double a, double b) {return ::pow(a, b); });
If lambdas are not available, one could try to make a functor (which lambda is equivalent to, please check https://medium.com/#winwardo/c-lambdas-arent-magic-part-1-b56df2d92ad2, https://medium.com/#winwardo/c-lambdas-arent-magic-part-2-ce0b48934809). Along the lines (untested code, I'm not at my computer)
struct pow_wrapper {
public: double operator()(double a, double b) {
return ::pow(a, b);
}
};
Then try
std::transform(base.cbegin(), base.cend(), exp.cbegin(), out.begin(), pow_wrapper());

How to resolve ambiguity between constructors taking std::string and std::vector

I want to make a "Tag" class that can have its name specified either as a dot separated name like "this.is.my.name" or as a vector of strings, like {"this","is","my","name"}.
When I try to do this, I am sometimes getting told by the compiler that my calls are ambiguous. I want to know (1) why this is ambiguous at all, and (2) why it is only ambiguous sometimes.
Here is my example code, which you can also view and compile here on Coliru
#include <string>
#include <vector>
#include <iostream>
class Tag
{
public:
explicit Tag(std::string name);
explicit Tag(std::vector<std::string> name);
};
Tag::Tag(std::string name)
{
//here 'name' will be a dotted collection of strings, like "a.b.c"
}
Tag::Tag(std::vector<std::string> name)
{
//here 'name' will be a vector of strings, like {"a","b","c"}
}
int main(int argc, char**argv)
{
Tag imaTag{{"dotted","string","again"}};
Tag imaTagToo{"dotted.string"};
//everything is fine without this line:
Tag imaTagAlso{{"dotted","string"}};
std::cout << "I made two tags" << std::endl;
}
With the indicated line, I get the following error:
g++ -std=c++11 -O2 -Wall -pthread main.cpp && ./a.out
main.cpp: In function 'int main(int, char**)':
main.cpp:28:39: error: call of overloaded 'Tag(<brace-enclosed initializer list>)' is ambiguous
Tag imaTagAlso{{"dotted","string"}};
^
main.cpp:18:1: note: candidate: 'Tag::Tag(std::vector<std::__cxx11::basic_string<char> >)'
Tag::Tag(std::vector<std::string> name)
^~~
main.cpp:13:1: note: candidate: 'Tag::Tag(std::__cxx11::string)'
Tag::Tag(std::string name)
^~~
Tag imaTagAlso{{"dotted","string"}}; says construct a Tag, call it imaTagAlso and initialize it with {"dotted","string"}. The issue with that is std::string can be constructed by a pair of iterators and since string literals can decay to const char*'s, they qualify as iterators. So you could either call the string constructor using the "iterators", or you could call the vector constructor using its std::initializer_list constructor. To work around this you can use
Tag imaTagAlso{{{"dotted"},{"string"}}};
which says construct a Tag, call it imaTagAlso and initialize it with {{"dotted"},{"string"}} and now {"dotted"} and {"string"} become elements of the std::initializer_list for the vector constructor.
You could also (since c++14) use std::string's user defined literal operator (""s) like
Tag imaTagAlso{{"dotted"s,"string"s}};
which makes each element of the braced-init-list std::string's, and the vector constructor will be chosen.

g++ invalid initialization error using boost::algorithm:string:split and std::string

I am porting some C++ code from Windows to Linux (and eventually OSX). Tons of C++ issues arise due to Windows non-compliance. I seem to have gotten past that, but am now facing a boost problem.
Basically, I want to chop up a string where the substrings of interest are separated by commas, and shove those into a string vector. This results in errors in g++, but it works fine compiling with Visual Studio
This program illustrates the issue exactly:
#include <boost/algorithm/string.hpp>
#include <string>
#include <vector>
int main (void) {
std::vector<std::string> str_vec;
std::string str_to_split = "this,is,the,string,to,split";
boost::algorithm::split(str_vec,
str_to_split.substr(1, str_to_split.size()-2),
boost::algorithm::is_any_of(","),
boost::algorithm::token_compress_on);
return 0;
}
To compile I do: >> g++ -o foo foo.cpp
This is my terminal output:
foo.cpp: In function 'int main()':
foo.cpp:11:54: error: invalid initialization of non-const reference type 'std::basic_string<char>&' from an rvalue of type'std::basic_string<char>'
boost::algorithm::split(str_vec,str_to_split.substr(1, str_to_split.size()-2),boost::algorithm::is_an
^
In file included from /usr/include/boost/algorithm/string.hpp:23:0,
from foo.cpp:1:
/usr/include/boost/algorithm/string/split.hpp:140:35: note: initializing argument 2 of 'equenceSequenceT& boost::algorithm::split(SequenceSequenceT&, RangeT&, PredicateT, boost::algorithm::token_compress_mode_type) [with SequenceSequenceT = std::vector<std::basic_string<char> >; RangeT = std::basic_string<char>; PredicateT = boost::algorithm::detail::is_any_ofF<char>]'
inline SequenceSequenceT& split(
^
This function takes std::string& rather than std::string or const std::string&. That means you'll have to store the result of .substr in an intermediate variable then pass the variable to boost::algorithm::split. It'll be clearer code anyway.
FWIW, I have no idea why the function is designed this way. Seems odd to me but there you go.

I have a situation with compiler. When i run the code to strip a string of special characters it runs in one compiler but doesn't in another?

Here is the code that produces the error in g++ 4.6.3
for (int i = 0; i < strlen(chars); i++)
{
a.erase (remove(a.begin(), a.end(), chars[i]), a.end());
}
The error i get is
error: cannot convert 'std::basic_string<char>::iterator {aka __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >}' to 'const char*' for argument '1' to 'int remove(const char*)'
The code runs perfectly well in code blocks 12.11.
You need
#include <algorithm>
And use std::remove instead of remove.
Otherwise it tries to use the remove function which is useful to remove files and it accepts const char* as parameter.

‘virtual char std::ctype<wchar_t>::do_narrow(wchar_t, char) const’ is protected

I'm trying to convert wstring to string with use of locale facets but I got stuck on following error:
test_facet.cpp: In function ‘int main()’:
test_facet.cpp:14: error: invalid initialization of reference of type ‘std::ctype<wchar_t>&’ from expression of type ‘const std::ctype<wchar_t>’
/usr/include/c++/4.4/bits/locale_facets.h:1430: error: ‘virtual char std::ctype<wchar_t>::do_narrow(wchar_t, char) const’ is protected
test_facet.cpp:16: error: within this context
Source:
#include <iostream>
#include <string>
#include <locale>
#include <algorithm>
using namespace std;
int main()
{
locale loc("");
std::wstring Str = L"ěščřžýáíé";
std::string Str2;
ctype<wchar_t> &ct = std::use_facet<std::ctype<wchar_t> >(loc);
for(std::wstring::const_iterator It = Str.begin(); It < Str.end(); ++It)
ct.do_narrow(*It, 'X' );
std::cout << Str2 <<std::endl;
}
Could someone tell me, what I am dooing wrong?
Thanks
2 things:
1) use_facet returns reference to const, so you can't assign it to a non-const one. So declare ct as:
const ctype<wchar_t> &ct = ....
2) As the second error message states, do_narrow is protected, making it unaccessible to external callers. Use narrowinstead, which is public.
You cannot invoke do_narrow from this context. Only member methods of class ctype (and deriveds) are allowed to call do_narrow.