C++ find_if with predicate isalpha gives error - c++

I can't understand why I have this error, apparently the isalpha function is redeclared twice (my editor marks me: "2 more overloads") but I don't understand why, this is my code:
#include <iostream>
#include <set>
#include <algorithm>
#include <ctype.h>
#include <string>
using namespace std;
int main(){
cin.tie(nullptr);ios_base::sync_with_stdio(false);
string line;
string::iterator prev, act;
while(cin>>line){
// act = find_if(line.begin(), line.end(), [](int x) {return isalpha(x);}); // GOOD
act = find_if(line.begin(), line.end(), isalpha); // ERROR
cout<<*act<<endl;
}
}
I use g++ (MinGW.org GCC-6.3.0-1) 6.3.0
Error:
1215.cpp: In function 'int main()':
1215.cpp:14:56: error: no matching function for call to 'find_if(std::__cxx11::basic_string<char>::iterator, std::__cxx11::basic_string<char>::iterator, <unresolved overloaded function type>)'
act = find_if(line.begin(), line.end(), isalpha); // ERROR
^
In file included from c:\mingw\lib\gcc\mingw32\6.3.0\include\c++\algorithm:62:0,
from 1215.cpp:3:
c:\mingw\lib\gcc\mingw32\6.3.0\include\c++\bits\stl_algo.h:3808:5: note: candidate: template<class _IIter, class _Predicate> _IIter std::find_if(_IIter, _IIter, _Predicate)
find_if(_InputIterator __first, _InputIterator __last,
^~~~~~~
c:\mingw\lib\gcc\mingw32\6.3.0\include\c++\bits\stl_algo.h:3808:5: note: template argument deduction/substitution failed:
1215.cpp:14:56: note: couldn't deduce template parameter '_Predicate'
act = find_if(line.begin(), line.end(), isalpha); // ERROR
Note: if I don't use the "using namespace std" the code compiles and executes correctly.
Thanks in advance for any answers or advice

This is what might be happening.
There's an isalpha() in the <cctype> header under the std namespace and another isalpha() in the <locale> header under the very same std namespace. using namespace std pulls both into the your scope and thus the ambiguity while deducing the template.
Moral of the story: Avoid using using namespace std.

I can't understand why I have this error, apparently the isalpha function is redeclared twice (my editor marks me: "2 more overloads") but I don't understand why
Two overloads are declared, because the standard says that there are two overloads.
A good solution is to use a lambda, as you did in the comment. Unlike creating a function pointer, calling the function in the lambda allows the call to be resolved to the correct overload based on the passed arguments.
Your lambda should be improved though: Change the type of the parameter to unsigned char. This is needed because char may be a signed type, and if the value of a char is negative, then it will have a value outside the range of unsigned char, and passing a value outside the range of unsigned char into islpha will result in undefined behaviour. Fixed example:
auto isalpha = [](unsigned char c){
return std::isalpha(c);
};
act = find_if(line.begin(), line.end(), isalpha);
Also, remove the line using namespace std.

To complete # Zoso's answer:
Inside <iostream> are included <cctype> and locale_facets.h both define different std::isalpha functions .
Also, inside <cctype> includes <ctype.h> (which is in fact explicitly included in the example) and <ctype.h> defines an isalpha function (without the std namespace).
So one way to solve the problem is to call the isalpha function of<ctype.h>, for this it is necessary to exit the current namespace (std) with :: operator.
This code works:
#include <iostream>
#include <algorithm>
#include <ctype.h>
#include <string>
using namespace std;
int main(){
cin.tie(nullptr);ios_base::sync_with_stdio(false);
string line;
string::iterator prev, act;
while(cin>>line){
act = find_if(line.begin(), line.end(), ::isalpha);
cout<<*act<<endl;
}
}

Related

adding <iostream> breaks the code in g++-7

There is sample
// Example 2: Will this compile?
//
// In some library header:
namespace N { class C {}; }
int operator+(int i, N::C) { return i+1; }
// A mainline to exercise it:
#include <numeric>
int main()
{
N::C a[10];
std::accumulate(a, a+10, 0);
}
From "Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions" -- Item 34. Name Lookup and the Interface Principle—Part 4
g++ 5.4 compiles it successfully.
But adding #include <iostream> breaks the code
// Example 2: Will this compile?
//
// In some library header:
namespace N { class C {}; }
int operator+(int i, N::C) { return i+1; }
// A mainline to exercise it:
#include <numeric>
#include <iostream>
int main()
{
N::C a[10];
std::accumulate(a, a+10, 0);
}
clang-4.0 is able to compile it. g++ 5.4 and g++7.2.0 show he following error
In file included from /usr/include/c++/7/numeric:62:0,
from src/widget.cpp:7:
/usr/include/c++/7/bits/stl_numeric.h: In instantiation of ‘_Tp std::accumulate(_InputIterator, _InputIterator, _Tp) [with _InputIterator = N::C*; _Tp = int]’:
src/widget.cpp:12:35: required from here
/usr/include/c++/7/bits/stl_numeric.h:127:18: error: no match for ‘operator+’ (operand types are ‘int’ and ‘N::C’)
__init = __init + *__first;
~~~~~~~^~~~~~~~~~
Looks like bug in g++. I'm interested to know if workaround exists?
IF somebody as curios as me - I'm posting what I have understood from further reading in the book.
Compiler will look for operator+ called from std::accumulate starting with namespace std.
Only if no candidates found in the namespace - it will go up and look for global namespace candidates.
So original sample and modified sample in clang were compiled by pure luck that no operator+ was declared before std::accumulate.
As soon as new header was added to the game - compiler stopped to look into the global namespace and stopped seeing proper operator as candidate at all.
Best match was not so good and cause all this strange error messages.
Now moving operator+ into namespace N was initiating Koenig lookup - if one of the function arguments is in the namespace N - suitable candidates should be looked in this namespace as well as addition to regular lookup.

std::isgraph is ambiguous when `using namespace std` is used

I tried to use std::isgraph from <cctype> as a predicate in find_if. But compiler errored out saying:
error: no matching function for call to ‘find_if(__gnu_cxx::__normal_iterator< const char*, std::basic_string< char> >, __gnu_cxx::__normal_iterator< const char*, std::basic_string< char> >, < unresolved overloaded function type>)’
I have used using namespace std; and from my understanding there will be two isgraph functions visible in the global namespace. So ::isgraph or simply isgraph should be ambiguous and std::isgraph should not be ambiguous. On the contrary, using ::isgraph is OK while std::isgraph is not.
Can someone explain what I missed? A few related questions are What are the function requirements to use as the predicate in the find_if from the <algorithm> library? and C++ using standard algorithms with strings, count_if with isdigit, function cast. But they didn't answer why explicitly specifying std:: still doesn't resolve to the function in the std namespace.
EDIT:
#include <cctype>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;
int main()
{
string root_line = "hello";
auto ind = distance(root_line.begin(), find_if(root_line.begin(), root_line.end(), std::isgraph));
cout << ind;
return 0;
}
I compiled the above code with g++ -std=c++11 of version 4.8.4
std::isgraph is overloaded.
To resolve the ambiguity you could cast it to the relevant function pointer type.
But in order to use it correctly the argument should be converted to unsigned char, so better define a wrapper function:
using Byte = unsigned char;
auto is_graphical( char const ch )
-> bool
{ return !!isgraph( Byte( ch ) ); }
Note that this only works with single-byte encodings, and that it depends on the current locale at the C level (see setlocale).
There is a std::isgraph defined in <cctype> and a different std::isgraph defiend in <locale>. Using overloaded functions as functors can be a pain as the compiler has difficulty figuring out which version of the function you want. You can resolve the ambiguity by casting, or using a lambda or named wrapper function as suggested by #Cheersandhth.-Alf
#include <cctype>
#include <algorithm>
#include <string>
#include <iostream>
int main()
{
std::string root_line = "hello";
auto ind = std::distance(root_line.begin(), std::find_if(root_line.begin(), root_line.end(), static_cast<int(*)(int)>(std::isgraph)));
std::cout << ind;
}
Live example: http://ideone.com/heSSEZ

Different use of scope operator

To transform a string and make it lowercase, we might do the following:
#include <iostream>
#include <algorithm>
#include <string>
#include <cctype>
using namespace std;
int main()
{
string str("Sample STRING");
cout << str << endl;
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
cout << str << endl;
return 0;
}
I know what std::transform is all about; but what's the scope operator :: doing in front of the function tolower?
If I remove the scope operator then the compiler complains of a function mismatch. If I add std in front of the :: operator then the compiler also complains of a function mismatch. What is the purpose of the scope operator in front of tolower? I don't know what it's called, and I searched everywhere for an explanation but to no avail.
You should #include <algorithm> to use std::transform.
The tolower function you want is defined in ctype.h or cctype. You should include one of these headers. The former declares tolower in the global namespace; the latter declares it in the std namespace.
It's likely that without the ::, you're picking up the function template std::tolower declared in the <locale> header. Of course, this only happens because you have using namespace std;. This is a particular example of how using namespace std; can be dangerous.
The :: with nothing on the left means the name to the right will be "looked up in global scope" and will find the global tolower rather than std::tolower. (Therefore, you should #include <ctype.h> to make sure you get the global declaration.)
:: without a left side bypasses looking in all accessible sub-scopes and forces the use of the root (or global) scope.

BOOST_PHOENIX_ADAPT_FUNCTION causes invalid template error

I am trying to create a lazy function from a template function following the Boost::phoenix documentation. The code looks like this
#include <iostream>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/function.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/statement.hpp>
#include <boost/phoenix/object.hpp>
#include <boost/phoenix/function/adapt_function.hpp>
#include <boost/phoenix/core/argument.hpp>
using namespace boost;
using namespace boost::phoenix;
namespace demo
{
bool func(double a,double b)
{
return bool(a > b);
}
}
BOOST_PHOENIX_ADAPT_FUNCTION( bool , func , demo::func , 2)
int main(int argc,char **argv)
{
namespace pl = boost::phoenix::placeholders;
auto comperator = func(pl::arg1,pl::arg2);
std::cout<<comperator(1.2,12.4)<<std::endl;
std::cout<<comperator(0.5,0.1)<<std::endl;
}
This is virtually one of the examples from the BOOST documentation. Storing this file as mk_lazy1.cpp and try to compile gives
$ g++ -omk_lazy1 mk_lazy1.cpp
mk_lazy1.cpp:26:1: error: template argument 1 is invalid
mk_lazy1.cpp:26:1: error: expected identifier before ‘::’ token
mk_lazy1.cpp:26:1: error: expected initializer before ‘const’
mk_lazy1.cpp: In function ‘int main(int, char**)’:
mk_lazy1.cpp:31:10: error: ‘comperator’ does not name a type
mk_lazy1.cpp:32:35: error: ‘comperator’ was not declared in this scope
I use gcc-4.7 on a Debian testing system. An honestly I am a bit lost as I have absolutely no idea what is wrong here (as I said, this is virtually a word by word copy of one of the examples provided by the Boost documentation).
Does anyone have a good idea?
Remove using namespaces and all will work fine.
Or write using namespaces AFTER adapt macro and all will work fine too.
Or put macro into unnamed namespace.

Whats going on here with cctype?

To my surprise the following code compiles:
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
#include <cctype>
int main() {
std::string s="nawaz";
std::string S;
std::transform(s.begin(),s.end(), std::back_inserter(S), ::toupper);
std::cout << S ;
}
I had expected it to fail because of the ::toupper which I believed should be in the std namespace. A quick check of cctype shows that it is but it is imported from the root namesapce (Mystery solved there).
namespace std
{
// Other similar `using` deleted for brevity.
using ::toupper;
}
So first problem solved but if I change the transform() line above too:
std::transform(s.begin(),s.end(), std::back_inserter(S), std::toupper);
I would now expect this to now also compile. But I get a compiler error:
kk.cpp:12: error: no matching function for call to `transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::cha
r_traits<char>, std::allocator<char> > >, std::back_insert_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)'
Which with manual editing resolved too:
kk.cpp:12: error: no matching function for call to
`transform(iterator<std::string>,
iterator<std::string>,
std::back_insert_iterator<std::string>,
<unresolved overloaded function type>)'
What am I missing?
It doesn't work because there are overloads of std::toupper. You can fix it by casting to your desired function overload:
std::transform(s.begin(),s.end(), std::back_inserter(S),
(int(&)(int))std::toupper);
You're missing that C++ also adds new toupper functions in <locale> which is probably included implicitly by one of your other headers. Thus in the std:: namespace there are multiple overloads while in the global namespace there is only the old C version of the function.
That said it does still seem like g++ should be able to deduce the correct overload.
Like others said the problem is that std::toupper and friends are overloaded.
One way to fix this is to use a lambda.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
int main()
{
std::string s{ "This is a test" };
std::string S{};
std::transform(s.begin(), s.end(), std::back_inserter(S), [] (char ch){ return std::toupper(ch); });
std::cout << S;
return 0;
}
I realize this is an old post but as many, including myself, still encounter this issue, I hope my post will be helpful.