Why compiler selects wrong overload in this case? - c++

Consider this rather simple code (godbolt):
#include <cstddef>
#include <string>
using namespace std;
string f(char const* fmt, ...);
size_t f(char* buf, size_t sz, char const* fmt, ...);
void bar()
{
f("%c%s", 'A', "AAA");
}
Type of first parameter is supposed to be char const[5], which means second overload should not be even considered. And yet compiler (even though it complains a bit) selects it (as you could see in generated assembly).
Can someone explain exactly what happens here?
Notes:
MSVC fails to compile this
my GCC version 8.3.1-3 fails to compile it too

Related

Need help using strncpy() in C++

I am stuck for hours during my assignment. Specifically, on this part:
The constructor should take a const-qualified C-Style string as its argument. Use the strncpy() function from the <cstring> library to copy it into the underlying storage. Be sure to manually null-terminate the attribute after you copy to assure that it is a valid C-String (in case the parameter contained a much larger string).
Where am I making mistakes, and how should I change my code?
#ifndef STRINGWRAPPER_H
#define STRINGWRAPPER_H
class StringWrapper{
public:
StringWrapper (const char myString);
const static int max_capacity = 262144;
private:
int size = 1;
char myString [40];
};
#endif
#include "StringWrapper.h"
#include <cstring>
StringWrapper::StringWrapper (const char myString){
strncpy(StringWrapper::myString, myString, sizeof(myString));
}
#include <iostream>
#include "ThinArrayWrapper.h"
#include "ArrayWrapper.h"
#include "StringWrapper.h"
#include <stdexcept>
int main(){
char myString[]{ "string" };
StringWrapper StringWrapper('h');
return 0;
}
First of all, your call to strncpy is wrong. Please check the reference regarding the strncpy from here.
According to the definition of strncpy :
char *strncpy(char *dest, const char *src, std::size_t count);
In your case, you are calling strncpy like this:
strncpy(StringWrapper::myString, myString, sizeof(myString));
Here, myString is a const char type variable. You need to make it to const char *. If you like, you can check my modification of your code from here.

Boost function map to string

I am trying to map a string to a function. The function should get a const char* passed in. I am wondering why I keep getting the error that
*no match for call to ‘(boost::_bi::bind_t<boost::_bi::unspecified, void (*)(const char*), boost::_bi::list0>) (const char*)’*
My code is below
#include <map>
#include <string>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
typedef boost::function<void(const char*)> fun_t;
typedef std::map<std::string, fun_t> funs_t;
void $A(const char *msg)
{
std::cout<<"hello $A";
}
int main(int argc, char **argv)
{
std::string p = "hello";
funs_t f;
f["$A"] = boost::bind($A);
f["$A"](p.c_str());
return 0;
}
In your example, using boost::bind is completely superfluous. You can just assign the function itself (it will converted to a pointer to a function, and be type erased by boost::function just fine).
Since you do bind, it's not enough to just pass the function. You need to give boost::bind the argument when binding, or specify a placeholder if you want to have the bound object forward something to your function. You can see it in the error message, that's what boost::_bi::list0 is there for.
So to resolve it:
f["$A"] = boost::bind($A, _1);
Or the simpler
f["$A"] = $A;
Also, as I noted to you in the comment, I suggest you avoid identifiers which are not standard. A $ isn't a valid token in an identifier according to the C++ standard. Some implementations may support it, but not all are required to.

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

Why is compiling this code producing an error?

I believe this is the right header:
#include <cstdio>
Note, there is a difference between the above declaration and this one:
#include <stdio.h>
The first one puts everything in the "std" namespace, the 2nd one doesn't. So I am using the first one.
Below is the code which I am compiling using g++4.4.6 on aix6.1:-
#include <cstdarg> //< va_list
#include <cstdio> //< vsnprintf()
#include "virtual_utils.h"
namespace VS
{
const char* format_str( const char* str, ... ) throw()
{
static char buf[10][1024];
static unsigned long buf_no = 0;
char* cur_buf = buf[ ++buf_no % 10 ];
buf_no %= 10;
va_list vl;
va_start( vl, str );
#ifdef _MSC_VER
std::_vsnprintf( cur_buf, sizeof(buf), str, vl );
#else
std::vsnprintf( cur_buf, sizeof(buf), str, vl );
#endif
return cur_buf;
}
} //< namespace VS
These are the following errors which I am getting:-
virtual_utils.C: In function 'const char* VS::format_str(const char*, ...)':
virtual_utils.C:28: error: 'vsnprintf' is not a member of 'std'
Edit:
Modifying the above code to remove the #include "virtual_utils.h" and to add a main(), it compiles with a warning under gcc4.3.4 on Ideone and cleanly under gcc4.5.1.
Compile with --save-temps, and examine the .ii file it produces. That should make it clear what's defined in what namespace, and what isn't.

Error declaring hash_map in lex file

I'm working on writing a simple preprocessor for a compiler. Below is an edited snippet of my code:
%{
#include <string.h>
#include <hash_map>
#include "scanner.h"
#include "errors.h"
struct eqstr {
bool operator()(const char* s1, const char* s2) const {
return strcmp(s1, s2) == 0;
}
};
std::hash_map<const char*, char*, hash<const char*>, eqstr> defs; // LINE 28
%}
// Definitions here
%%
// Patterns and actions here
%%
When I compile I get the following error:
dpp.l:28: error: expected constructor,
destructor, or type conversion before
‘<’ token
Any ideas what might be wrong with this? I pretty much copied and pasted this line from the sgi documentation.
You need std::hash rather than just hash, since you have no using statement that will pull it into scope. Also, the default std::hash<const char *> will hash the pointer directly, which won't work for this use -- you need a hash function that hashes the c-string pointed at. You need to define your own specialization of hash, or your own hashing function -- the latter is probably better.