How to you do a string comparison in a to a value in a vector<std::string>?
I tried str, the error is printed below.
.....
vector<std::string> dat;
vector<std::string> pdat;
dat = my();
for(int b = 2; b < dat.size(); b+=7){
// cout << dat[b] << " " << endl;
if(!strcmp(dat[b], "String\n"){ // The error is here
pdat.push_back(dat[b]);
}
}
my.cpp: In function 'std::vector > ngr()':
my.cpp:53:32: error: cannot convert '__gnu_cxx::__alloc_traits > >::value_type {aka std::basic_string}' to 'const char*' for argument '1' to 'int strcmp(const char*, const char*)'
std::string is compared with plain ==. This works because the == operator is overloaded to do a string comparison for std::strings.
if (dat[b] == "String\n") {
If you're dealing with C++ strings, you shouldn't need any of the str* functions from string.h, so you might as well not include it at all.
Simply use operator== on to compare an std::string and a const char* :
if(dat[b] == "String\n"){ //
pdat.push_back(dat[b]);
}
For the record, the exact overload used here is the function template :
template< class CharT, class traits, class Alloc >
bool operator==( const basic_string<CharT,Traits,Alloc>& lhs, const CharT* rhs );
strcmp (that you dont need here, and rarely need in C++) expects const char* arguments :
int strcmp( const char *lhs, const char *rhs );
So you could (but shouldn't) invoke it with th help of the c_str() member function :
if(!strcmp(dat[b].c_str(), "String\n")
...
strcmp() expects 2 const char*s but dat[b] is a string, so you aren't comparing apples with apples.
You can either do
if(!strcmp(dat[b].c_str(), "String\n"){
Or
if (dat[b] == "String\n") {
The second is the more C++ approach.
Related
I've overloaded my function contains three times
// returns true if char c is contained in unordered map um
bool contains(std::unordered_map<char, op>& um, char c){
return um.find(c) != um.end();
}
// returns true if string s is contained in unordered map um
bool contains(std::unordered_map<char, op>& um, std::string& s){
return s.length() == 1 && contains(um, s[0]);
}
// returns true if string s is contained in unordered map um
bool contains(std::unordered_map<std::string, func>& um, std::string& s){
return um.find(s) != um.end();
}
The parameters are different in each overloaded function. Yet, from the line (contains(opmap, q_front)) I get the error: more than one instance of overloaded function "contains" matches the argument list.
For reference, opmap is of type std::unordered_map<char, op>, and q_front is a string. op in this case is just struct I created- I can post if needed, but I feel it is unnceessary in this case.
My question is why I'm getting this error, as the function call above should uniquely call the second method header: bool contains(std::unordered_map<char, op>& um, std::string& s){ because of the type of opmap matches the first parameter, and the type of q_front is string.
UPDATE:
Full error message:
more than one instance of overloaded function "contains" matches the argument list: -- function "contains(std::unordered_map<char, op, std::hash<char>, std::equal_to<char>, std::allocator<std::pair<const char, op>>> &um, std::string s)" (declared at line 48 of "/Users/raleighclemens/Documents/Calc_cpp/calc.h") -- function "contains(std::unordered_map<char, op, std::hash<char>, std::equal_to<char>, std::allocator<std::pair<const char, op>>> &um, std::string &s)" (declared at line 49) -- argument types are: (std::unordered_map<char, op, std::hash<char>, std::equal_to<char>, std::allocator<std::pair<const char, op>>>, std::string)C/C++(308)
MRE:
#include <iostream>
#include <string>
#include <functional>
#include <unordered_map>
#define LEFT 0
#define RIGHT 1
#define UNARY 0
#define BINARY 1
struct op{
char symbol;
uint8_t precedence;
uint8_t assoc;
uint8_t type;
std::function<double (double, double)> ashley;
};
struct func{
std::string symbol;
uint8_t type;
std::function<double (double, double)> ashley;
};
bool contains(std::unordered_map<char, op>& um, char c){
return um.find(c) != um.end();
}
// returns true if string s is contained in unordered map um
bool contains(std::unordered_map<char, op>& um, std::string& s){
return s.length() == 1 && contains(um, s[0]);
}
// returns true if string s is contained in unordered map um
bool contains(std::unordered_map<std::string, func>& um, std::string& s){
return um.find(s) != um.end();
}
int main(int argc, char** argv){
std::unordered_map<char, op> opmap;
op op1{'+', 2, LEFT, BINARY, [=] (double a, double b){return a + b;}};
opmap.emplace('+', op1);
std::cout << contains(opmap, "+");
Which overload you expect to match your call to the below line?
std::cout << contains(opmap, "+");
Overload 1 cannot match, because of your second argument, i.e. "+". Its type is const char[2] and cannot be matched to char.
Overload 2 and 3 cannot match, because the type of "+" has a const qualifier, but in those two overloads your string is passed as a non-const reference.
So, to fix your issue, you should either:
change "+" to '+' to use the first overload.
change std::string & to const std::string & to use overload 2.
I try to sort a structure but I have this error :
error: cannot convert ‘std::vector<Node>’ to ‘void*’ for argument ‘1’ to ‘void qsort(void*, size_t, size_t, __compar_fn_t)’
qsort(nodes,nodes.size(), sizeof(Node), dataClustering::compare);
This is my code :
compare function :
int compare(const void * node1, const void * node2){
string name1 = ((const struct Node*)node1)->name;
string name2 = ((const struct Node*)node2)->name;
int start1 = ((const struct Node*)node1)->start;
int start2 = ((const struct Node*)node2)->start;
if(name1 <= name2 && start1 <= start2){
return -1;
}
else if(name1 > name2 && start1 > start2){
return 1;
}
else{
return 0;
}
}
Call of compare in another function :
qsort(allNodes,allNodes.size(), sizeof(Node), compare);
And the header in .hpp file (I try to put it in static but this don't solve the error):
int compare(struct Node *, struct Node *);
You can pass vector to C-style sort, for example, like this:
qsort(&allNodes[0], allNodes.size(), sizeof(Node), compare);
You would be better off using std::sort, which works with vectors natively:
bool compareNodes(const Node& lhs, const Node& rhs) {
return (lhs.name < rhs.name)
|| (lhs.name == rhs.name && lhs.start < rhs.start);
}
...
std::sort(allNodes.begin(), allNodes.end(), compareNodes);
in C++11/C++14 you can define comparison as a lambda, too:
std::sort(allNodes.begin(), allNodes.end(), [] (const auto& lhs, const auto& rhs) {
return (lhs.name < rhs.name)
|| (lhs.name == rhs.name && lhs.start < rhs.start);
});
(the code above uses auto for lambda arguments, a C++14 feature).
The error is that you
cannot convert ‘std::vector<Node>’ to ‘void*’
and thus, a std::vector<Node> cannot possibly be a suitable first argument to a function like qsort with signature
void (void*, size_t, size_t, __compar_fn_t)
While there are things you could do to use qsort here, you really shouldn't: you should use std::sort from the C++ standard library:
using std::sort;
sort(begin(allNodes), end(allNodes), compare_function);
Here, compare_function should be a function that acts like < and takes two arguments of the appropriate type (e.g. the actual type of the objects you're sorting or const references to them, not pointers to them or void pointers) and returns bool if the first argument is less than the second. (compare_function doesn't actually have to be a function: it can also be any object that has an appropriate operator() or a lambda)
If you want to just sort, use
#include <algorithm>
...
bool myfunction (const Node &lhs, const Node &lhs) {
if(lhs.name < rhs.name) return true;
return (lhs.name == rhs.name && lhs.start < rhs.start));
}
...
std::sort(allNodes.begin(), allNodes.end(), compare_func);
Further read: std::sort
If you want to use cstyle qsort(which I suggest you should not), add a wrapper function to do the conversion of void * to Node * and change the first argument of qsort to static_cast<void *>(&allNodes[0])
I have a simple wrapper around C null-terminated string, which is essentially a subclass of std::vector< char >. (Yes, I know about std::string, but my wrapper is easier to cooperate with C functions expecting char*. Also, std::string isn't guaranteed to be contiguous in C++03)
Here is the code:
#include <cstdio>
#include <vector>
typedef std::vector<char> vector_char;
class c_string : public vector_char
{
public:
c_string(size_t size) : vector_char(size+1) {}
c_string(const char* str)
{
if(!str) return;
const char* iter = str;
do
this->push_back(*iter);
while(*iter++);
}
c_string() {}
//c_string(std::nullptr_t) {}
char* data()
{
if(this->size())
return &((*this)[0]); //line 26
else
return 0;
}
const char* data() const { return this->data(); }
operator char*() { return this->data(); }
operator const char*() const { return this->data(); }
};
int main()
{
c_string first("Hello world");
c_string second(1024);
printf("%s",first.data());
printf("%c\n",first[0]);
snprintf(second, second.size(), "%d %d %d", 5353, 22, 777);
printf(second);
}
MinGW complains about:
D:\prog\PROJEKTYCPP\hehe_testc_cpp.cpp: In member function 'char* c_string::data()':
D:\prog\PROJEKTYCPP\hehe_testc_cpp.cpp:26:22: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default]
In file included from d:\prog\mingw\bin\../lib/gcc/mingw32/4.7.0/include/c++/vector:65:0,
from D:\prog\PROJEKTYCPP\hehe_testc_cpp.cpp:2:
d:\prog\mingw\bin\../lib/gcc/mingw32/4.7.0/include/c++/bits/stl_vector.h:768:7:note: candidate 1: std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::operator[]:(std::vector<_Tp, _Alloc>::size_type) [with _Tp = char; _Alloc = std:
:allocator<char>; std::vector<_Tp, _Alloc>::reference = char&; std::vector<_Tp,_Alloc>::size_type = unsigned int]
D:\prog\PROJEKTYCPP\hehe_testc_cpp.cpp:26:22: note: candidate 2: operator[](char
*, int) <built-in>
How can I enforce calling correct overload? Can this problem hurt me silently?
By having an operator char * you've provided two ways to do operator[]. The first is std::vector::operator[] applied directly; the second is to convert this to char* and apply [] to that. In this case they both result in the same thing, but the compiler can't know that.
Resolve it by specifying explicitly which one you want.
return &(operator[](0)); //line 26
or
return &((char*)(*this)[0]); //line 26
To delete the first warning, you can do this:
char* data()
{
if(this->size())
return &vector_char::operator[](0);
else
return 0;
}
To delete all warnings, remove the operator char*() and operator const char*() members.
Thanks for your view but this problem has been solved! I didn't have the parameters in the right order. Have a good evening!
For some reason the objects from the class named TimerEvent keep setting
error C2665: 'TimerEvent::TimerEvent' : none of the 2 overloads could convert all the argument types
But as far as I know there is no overload.
Please look at the code and let me know if you have any insight. Ty.
class TimerEvent {
public:
char primary;
int secondary;
string item;
int socketno;
int eventnumber;
int expirytime;
bool eventvalid;
TimerEvent(string td, int sno = 0, int evnum = 0, int exptime = 0, bool evvalid = false, char pri = 'A', int sec = 1)
: primary(pri), secondary(sec), socketno(sno), eventnumber(evnum), expirytime(exptime), eventvalid(evvalid), item(td) {}
friend bool operator<(
const TimerEvent& x, const TimerEvent& y) {
if(x.primary > y.primary)
return true;
if(x.primary == y.primary)
if(x.secondary > y.secondary)
return true;
return false;
}
friend ostream&
operator<<(ostream& os, const TimerEvent& td) {
return os << td.primary << td.secondary
<< ": " << td.item << td.socketno << td.eventnumber << td.expirytime << td.eventvalid;
}
};
And here's the other half
if( comsent.compare( "test" ) == 0 ) {
timerqueue.push(TimerEvent( 'A', 2, 10, 1, 0, true, "Alright"));
// The above is setting the error
cout << " Top Value Is: " << timerqueue.top().socketno << endl;
}
In the class you define the constructor to take its first argument as a string, but when you construct the object you pass a character not a string. You also pass a string as the argument pri which in the definition is a char.
It's a simple case of having to many arguments, and not remembering the exact order. Try to have a constructor with less arguments, and add functions to set values after construction. It will use more lines of code, but will be much more readable in the future.
Formally, there are two overloads for TimerEvent::TimerEvent: the
constructor you defined, and the copy constructor. For overloading
purposes, there are even more, since the presence of a default argument
is treated like an overload. Given that, the compiler will consider the
following overloads:
TimerEvent( string, int, int, int, bool, char, int )
TimerEvent( string, int, int, int, bool, char )
TimerEvent( string, int, int, int, bool )
TimerEvent( string, int, int, int )
TimerEvent( string, int, int )
TimerEvent( string, int )
TimerEvent( string )
TimerEvent( TimerEvent const& )
n the push statement, you call with:
TimerEvent( char, int, int, int, int, bool, char const[] )
Neither the first nor the last argument can match: there is no way to
convert a char to either a string or a TimerEvent, and there is no
way to convert a char const[] to an int. Some of the other
conversions asked for are surprising as well: the fifth argument
requires an int to bool conversion (unexpected for a literal), and
the sixth a bool to char (very, very unexpected, resulting in either
'\0' or '\1').
Consider this code:
template <typename T>
class String
{
public:
...
String(T* initStr)
{
size_t initStrLen;
if (initStr != NULL)
{
printf_s("%s\n", typeid(T) == typeid(char) ? "char" : "wchar_t");
if (typeid(T) == typeid(char))
{
strlen((T*)initStr);
}
else if (typeid(T) == typeid(wchar_t))
{
wcslen((T*)initStr);
}
}
}
...
};
When I compiled the code, I got this error message:
...\main.cpp(32) : error C2664: 'strlen' : cannot convert parameter 1 from 'wchar_t *' to 'const char *'
Then I tried to use a function pointer:
typedef size_t (*STRLEN)(void*);
STRLEN _strlen;
_strlen = reinterpret_cast<STRLEN> (typeid(*initStr) == typeid(char) ? strlen : wcslen);
and again the compiler issued an error, this time:
...\main.cpp(28) : error C2446: ':' : no conversion from 'size_t (__cdecl *)(const wchar_t *)' to 'size_t (__cdecl *)(const char *)'
My question is, how can I use the functions strlen and wcslen with templates?
You can do this e.g. by introducing a helper function as illustrated below:
#include <iostream>
#include <string.h>
size_t GetLength(const char* s) { return strlen(s); }
size_t GetLength(const wchar_t* s) { return wcslen(s); }
template <typename T>
void PrintLength(T s)
{
std::cout << GetLength(s) << std::endl;
}
int main()
{
PrintLength("abc");
PrintLength(L"abc");
}
Use this helper function GetLength instead of strlen or wcslen and don't check the type of the argument explicitly. You can write overloads of GetLength for other types as well, e.g. std::string.
You rarely need to use typeid in practice and in this case it is completely inappropriate.
You can't use if statements to control what code is instantiated for a template: all of the code in the body must work for every instantiation.
std::size_t strlen(wchar_t const *s) {
return std::wcslen(s);
}
//...
String(T* initStr) {
using std::strlen; // bring into scope so unqualified call can find it
std::size_t length = strlen(initStr); // uses std::strlen or our strlen
//...
You could also add an overload of your strlen for char, then you don't need the using declaration.
You have misunderstood templates. You should not use typeid to determine types here, but instead use template specialisation.
In case the OP is interested in how strings are implemented in STL, they use a whole helper class call char_traits. This is a class with nothing but static member functions, and char_traits is specialised for char and wchar_t to use the C runtime library functions like memmove.
For example you have a compare function that returns a value <0, 0 or >0. Where the type is char it can use memcmp. Where the type is wchar_t it can use the wide equivalent.
It works something like this:
template< typename Element >
class char_traits
{
public:
static int compare( const Element * left, const Element * right, size_t length )
{
for( const Element * end = left + length; left != end; ++left )
{
if( left < right )
return -1;
else if( left > right )
return 1;
}
return 0;
}
// other functions
};
template <> class char_traits<char> // I think this is the syntax
{
public:
int compare( const char * left, const char * right, size_t len )
{
return memcmp( left, right, len ); // more efficient than the general loop above
}
// other functions
};
// specialise also for wchar_t