STL error _without_ any STL in code - c++

I am using gcc 3.4.4 on cygwin. I am getting this rather perplexing STL error message in my code below which does not use STL at all:
#include <iostream>
using namespace std;
const int N = 100;
bool s[N + 1];
bool p[N + 1];
bool t[N + 1];
void find(const bool a[], bool b[], bool c[]){
return;
}
int main(){
find(s, p, t);
return 0;
}
When I compile with
g++ stack.cc
I get the following error message:
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h: In function `_RandomAccessIterator std::find(_RandomAccessIterator, _RandomAccessIterator, const _Tp&, std::random_access_iterator_tag) [with _RandomAccessIterator = bool*, _Tp = bool[101]]':
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:314: instantiated from `_InputIterator std::find(_InputIterator, _InputIterator, const _Tp&) [with _InputIterator = bool*, _Tp = bool[101]]'
stack.cc:18: instantiated from here
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:207: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:211: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:215: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:219: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:227: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:231: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:235: error: ISO C++ forbids comparison between pointer and integer
As you can see, the code does not use any STL at all, so this is rather strange. Also, the error disappears if I remove the line
using namespace std;
which hints at some namespace clash. It also disappears if I remove the const keyword from the definition o the function find.
On the other had the error also disappears (and this is rather surprising) if I make find a 2-argument function as follows:
#include <iostream>
using namespace std;
const int N = 100;
bool s[N + 1];
bool p[N + 1];
bool t[N + 1];
void find(const bool a[], bool b[]){
return;
}
int main(){
find(s, p);
return 0;
}
I can't imagine what could be the reason why find can be a two argument function but not a three argument one.
So here is a brief summary of the three ways to remove the error:
Remove the using namespace std; line.
Remove the const keyword from the definition of find.
Remove the third argument of the function find.
I cannot think of any logical reason why such an error should happen in the first place, and why it should get removed i I use any of the above seemingly completely unrelated steps. Is this a documented g++ bug? I tried searching for it, but honestly I was at a loss what to search for, and the few keywords I tried ("STL error without STL use") didn't turn up anything.

You simply have a collision, because you've unintentionally pulled std::find (which takes 3 arguments) into the global namespace when you did using namespace std;. For whatever reason, your <iostream> is #include-ing <algorithm>, or one of the parts of its internal implementation (specifically, bits/stl_algo.h).
I can't explain why removing const makes it go away; perhaps it affects the order in which the compiler resolves overloads.

You are confusing the compiler with the version of find that is in the standard library (std::find), which has 3 parameters, but not the ones you have.
If your code was in its own namespace, you could avoid this problem. Or by renaming your find method, or the solutions you have already documented.

Related

C++ error two or more data types in declaration of variable

I ran the following C program and got In as the output.
#include<stdio.h>
int main()
{
auto int i = 0;
if(++i)
printf("In");
else
printf("Out");
return 0;
}
But when I tried to run it as a C++ program by changing the header files and standard output, I got an error:
jdoodle.cpp: In function ‘int main()’:
jdoodle.cpp:6:14: error: two or more data types in declaration of ‘i'.
6 | auto int i = 0;
| ^.
jdoodle.cpp:7:10: error: ‘i’ was not declared in this scope.
7 | if(++i).
| ^
C++ code:
#include <iostream>
using namespace std;
int main() {
auto int i = 0;
if(++i)
cout<<"In";
else
cout<<"Out";
return 0;
}
In C, auto is an obsolete keyword it inherited from B. It is either implicitly assumed, or illegal to specify. So, it's basically never used.
C++ inherited this keyword from C as is, and your code would have compiled under C++98. In C++11 this keyword was repurposed to be used for implicit type deduction. It is now widely used but means something completely different and the way you tried to use it is illegal.
The point is, C and C++ are different languages. Writing code that compiles under C and C++ is difficult and requires care.
In the C++ program, for the line
auto int i = 0;
the auto keyword is being used to automatically deduce the type of variable i from its initialized value if compiling with C++11 or later. However, the line also includes int, which is also declaring the type. You can't use both of them -- you get the same error if you write double int i = 0; (i can't be both a double and an int) or int int i = 0; (it's the same type but you're declaring the type twice). Choose one or the other, i.e. either
auto i = 0;
or
int i = 0;
You can see that it works with C++98 but not C++11 or C++14 online here. Prior to C++11 the auto keyword was a storage class specifier.

template operator visibility, gcc vs clang

I have this code, relying on a fold expression calling a very generic comparison operator:
#include <type_traits>
#include <vector>
#include <list>
template <typename Iter_a, typename Iter_b>
auto operator<(Iter_a, Iter_b) {
// original code makes more sense, I assure you
if constexpr ( std::is_same_v<Iter_a, Iter_b> ) {
return Iter_a();
}
else return Iter_b();
}
template <typename... Iterators>
using weakest_iterator = std::decay_t<decltype( (Iterators() < ...) )>;
int main() {
using lit = std::list<int>::iterator;
using vit = std::vector<int>::iterator;
using wi = weakest_iterator<lit, vit, float*>;
}
I have two problems with this code:
The first is that g++ compiles it and clang++ (-std=gnu++2a) refuses to do so:
prog.cc:14:64: error: call to function 'operator<' that is neither visible in the template definition nor found by argument-dependent lookup
using weakest_iterator = std::decay_t<decltype( (Iterators() < ...) )>;
^
prog.cc:19:16: note: in instantiation of template type alias 'weakest_iterator' requested here
using wi = weakest_iterator<lit, vit, float*>;
^
prog.cc:6:6: note: 'operator<' should be declared prior to the call site
auto operator<(Iter_a, Iter_b) {
Do you have any idea why? I find particularly troubling that clang requests a definition prior to the call site at line 19, that it finds by itself at line 6.
The second is that, if I modify it to invoke my meta-function with pointer template arguments (using wi = weakest_iterator<int*, float*, float*>;, I get another error message, this time only with g++ since clang refuses to compile, that I find difficult to really understand:
main.cpp: In substitution of 'template<class ... Iterators> using weakest_iterator = std::decay_t<decltype ((Iterators() < ...))> [with Iterators = {int*, float*, float*}]':
main.cpp:19:57: required from here
main.cpp:14:75: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]
using weakest_iterator = std::decay_t<decltype( (Iterators() < ...) )>;
It seems that 1) the built-in overload of operator< is called (if there is anything such as this) over my ultra-generic one, and 2) that comparing an int* and a float* is considered the same as comparing a pointer and an integer.
Is it possible to make sure that my own implementation of operator< is chosen by the compiler?

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.

Why does a global merge() function conflict with std::merge()?

Consider the following code:
#include <vector>
#include <algorithm>
template <typename Input1, typename Input2, typename Output>
void merge(Input1 begin1, Input1 end1, Input2 begin2, Input2 end2, Output out)
{
}
int main()
{
std::vector<int> a = {1, 2};
int b[] = {3, 4};
int c[4];
merge(a.begin(), a.end(), b, b + 2, c);
}
Compiling yields:
$ clang++ -std=c++11 -stdlib=libc++ merge.cpp
merge.cpp:15:5: error: call to 'merge' is ambiguous
merge(a.begin(), a.end(), b, b + 2, c);
^~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/algorithm:4056:1: note:
candidate function [with _InputIterator1 = std::__1::__wrap_iter<int *>,
_InputIterator2 = int *, _OutputIterator = int *]
merge(_InputIterator1 __first1, _InputIterator1 __last1,
^
merge.cpp:5:6: note: candidate function [with Input1 = std::__1::__wrap_iter<int
*>, Input2 = int *, Output = int *]
void merge(Input1 begin1, Input1 end1, Input2 begin2, Input2 end2, Output out)
^
1 error generated.
Compiler version:
$ clang++ --version
Apple LLVM version 5.0 (clang-500.2.78) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.0
Thread model: posix
Why is the call to merge ambiguous? It's not sure if I meant ::merge() or std::merge(), though clearly(?) it should be ::merge() since I'm not specifying any using directives. My merge function is in the global namespace, which I thought wouldn't conflict with anything in the std namespace (since that's the main point of namespaces, right?). If I change a to be an int array like the others, it compiles without any ambiguity. Also, adding the colons and calling ::merge() works fine.
So my question is this: Is this a bug in Clang, or do I have a misunderstanding of namespaces? Why does my call to merge() result in ambiguity when the two functions aren't in the same namespace and I haven't made std::merge() visible with any using directives?
The problem is that std::vector<T>::iterator may be a class type (in your case, it is a class type): during overload resolution the compiler finds all visible declarations of a function. To this end, it goes looking in namespaces possibly associated with its arguments (this is called argument dependent look-up). The type std::vector<T>::iterator is defined in namespace std (or a namespace nested within) and, thus, function from namespace std are considered for overload resolutions. Since std::merge() and your merge() both match equally well, there is an ambiguity.
The easiest way to avoid the problem is to use a different name for the function template. Hiding the associated namespace is possible but not easy: associated namespaces are taken from the location where a class or a class template is defined as well as from its base classes and template arguments. Thus, creating a wrapper template for any iterator type wouldn't be sufficient as it still associates the original namespace with the types. You may try to make your function template a better match but given that it is meant to be as generic as the standard algorithm, this isn't quite viable, either.
It's due to argument dependent look-up (http://en.cppreference.com/w/cpp/language/adl) of an iterator from the std namespace.
you could write ::merge to get your function only, but I'd rather just use a different name.

G++ abs() on a short int appears to turn it into a double?

The following code does not compile if std::abs(angle) is present. The type of angle is in this case a short int.
template <class T>
typename T::storage_t::single_t FastSin(const typename T::storage_t::double_t &angle) {
const int B = (sizeof(typename T::storage_t::single_t)*8) - 2;
return (angle<<1) - ((angle*(std::abs(angle)))>>B);
}
A close look at the messages can verify that angle is in fact a short int. However, if I am reading the error correctly, GCC turns it into a double.
math.hpp: In function ‘typename T::storage_t::single_t FastSin(const typename T::storage_t::double_t&) [with T = Fixed<_t<signed char, short int> >, typename T::storage_t::single_t = signed char, typename T::storage_t::double_t = short int]’:
vector.hpp:106:30: instantiated from ‘void Vector2<T>::FastRotate(const single_t&) [with T = Fixed<_t<signed char, short int> >, Vector2<T>::single_t = signed char]’
test.cpp:9:18: instantiated from here
math.hpp:11:52: error: invalid operands of types ‘__gnu_cxx::__enable_if<true, double>::__type {aka double}’ and ‘const int’ to binary ‘operator>>’
What is going on here? Even return (angle<<1) - ((angle*(std::abs<int>(angle)))>>B); does the same.
I am using gcc version 4.6.1. The only external headers included are <cmath> and <cstdint>. The compilation flags are -std=c++0x -Wall.
abs() is not a template, but a set of overload functions. According to the standard, the overload for int, long, float, double, long double should exist. But the overload for short does not exist. But as the conversion sequence from short to int is only a promotion, and the conversion sequence form short to the other overloaded types are all conversions, the overload for int should be selected.
But in g++ (version 4.5.2 for me), a non-standard template is added to cmath:
template<typename _Tp>
inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
double>::__type
abs(_Tp __x)
{ return __builtin_fabs(__x); }
This template would take all built-in integral types other than int and long and give a return value of double.
As a matter of fact, using type unsigned int also produces this error in g++:
#include <cstdlib>
#include <cmath>
int main() {
unsigned int i,j;
i=0;
j=std::abs(i)>>2;
return 0;
}
Explicitly casting it to int (std::abs((int)i);) should solve this problem.
The std::abs() function isn't a template in C++; there are just several overloads provided for different types. The ones for the integral types are in the header <cstdlib>. See http://www.cplusplus.com/reference/clibrary/cstdlib/abs/ and http://www.cplusplus.com/reference/clibrary/cmath/abs/ for more info.
I know that this post is already answered long ago, but i just want to give another perspective which should help someone else. My problem was with QT and mingw, always when i build with boost or some other libraries which use cmath and cstdlib i got this error. After some time i was pretty annoyed with this error, and i decided to do a little research about those two files.
I totally agree with fefe and his answer but that can only solve problems if you use it in you program or library ,and you know from a start what is a problem, and that wasn't my problem.
If you really need to include both files in same time (you need system, malloc... and all math functions) quick and dirty fix is to open header and on 106 line (on my computer) you will see something like this:
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
using ::div_t;
using ::ldiv_t;
using ::abort;
//using ::abs;
using ::atexit;
using ::atof;
using ::atoi;
using ::atol;
using ::bsearch;
using ::calloc;
.
.
.
From code above you can see that cstdlib have function abs in std namespace and you need to comment that line in order to enable use of cmath abs function and to get rid of that nasty error.
I hope that this will help someone, and i am sorry for such a long post.