How to compare boost::string_ref to std::string - c++

I'm trying to make boost::string_ref working as I want to, but I'm facing a problem right now - following code does not compile:
#include <boost/utility/string_ref.hpp>
#include <iostream>
#include <string>
using namespace std;
int main() {
string test = "test";
boost::string_ref rtest(test);
cout << (rtest == "test")<<endl;
}
and the gcc throws 30kB error log, starting with
source.cpp: In function 'int main()':
source.cpp:10:19: error: no match for 'operator==' (operand types are 'boost::string_ref {aka boost::basic_string_ref<char, std::char_traits<char> >}' and 'const char [5]')
cout << (rtest == "test")<<endl;
^
How to compare boost::string_ref to std::string?

Honestly, I'd just avoid using string_ref entirely until it matures. The fact that you can't compare a string_ref to a std::string or a const char * out of the box should set alarm bells ringing (looks like they forgot to write a bunch of comparison operators), and worse, it doesn't look like the library received sufficient testing (e.g. bug 8067!).

Just make a string_ref out of the string. They are very cheap to construct. Though against a string literal, you may want to include the length. Otherwise it's going to iterate once to find the end of the string, and then iterate again to compare them. Just make sure that if you change the string, you keep the count up to date.
cout << (rtest == boost::string_ref("test",4)) << endl;
With a std::string, you don't need to worry about the count, because string_ref will just call the size() member function, which is also very cheap.

Related

What is no matching function for call to 'isPalindrome'?

top 35/3_palindrome.cpp:18:8: error: no matching function for call to 'isPalindrome'
if(isPalindrome(s)){
^~~~~~~~~~~~
top 35/3_palindrome.cpp:4:5: note: candidate function not viable: no known conversion from 'std::__1::string' (aka 'basic_string<char,
char_traits<char>, allocator<char> >') to 'char *' for 1st argument
int isPalindrome(char* s){
^
1 error generated.
The terminal process "/bin/zsh '-c', ' g++ -g 'top 35/3_palindrome.cpp' -o 3_palindrome.out && clear && ./3_palindrome.out'" terminated with exit code: 1.
My code:
#include <bits/stdc++.h>
using namespace std;
int isPalindrome(char* s){
int n = strlen(s);
for (int i = 0; i < n/2; i++){
if(s[i] != s[n - i - 1]){
return 0;
}
}
return 1;
}
int main(){
string s;
getline(cin,s);
cout << s;
if(isPalindrome(s)){
cout << "Yes";
}
else{
cout << "No";
}
return 0;
}
The Problem
Your isPalindrome function expects char * for its argument. There is no suitable implicit conversion (operator or otherwise) from what you're giving it, a std::string, to that char *. The compiler is dutifully pressing on and attempting to find an alternative overload of isPalindrome that matches what you're actually feeding it. Finding none, the resulting error halts the compile and leaves you with your not-necessarily-crystal-clear error message.
A Solution
There are a multitude of solutions, but the easiest is simply to change isPalindrome to accept a reference to const std::string:
bool isPalindrome(std::string const& s)
{
std::size_t n = s.length();
for (std::size_t i=0; i<n/2; ++i)
{
if(s[i] != s[n - i - 1])
return false;
}
return true;
}
A More-C++ Solution
All you're really doing is comparing two ranges. The standard library provides a function to do this, std::equal , which takes an iterator begin/end, and a secondary iterator starting point (and after C++14, a secondary ending point). Furthermore, the std::string class provides both fore and aft direction iterators (begin() and rbegin(), and the lot of them can be used to do this:
#include <iostream>
#include <string>
#include <algorithm>
bool isPalindrome(std::string const& s)
{
return std::equal(s.begin(), std::next(s.begin(), s.length()/2), s.rbegin());
}
Note that neither this, nor your original C-based approach, will work with mixed-case comparison. I.e. Aba will certainly not compare as a successful palindrome. More work is involved if you want that. Also, the three-argument overload of std::equal is available until, but not including, C++20, after that you need the four argument version (the second range also requires an end-iterator; not just a starting point).
Noteworthy
Neither #include <bits/stdc++.h> or using namespace std are good ideas, and should be avoided. There are woefully inadequate web sites and online "courses" that preach using both almost by reflex; just... don't. If you want know more about why these are terrible practices I urge you to read:
Why should I not #include <bits/stdc++.h>?
Why is “using namespace std;” considered bad practice?
Take a closer look at the error:
if(isPalindrome(s)){
palindrome.cpp:4:5: note: candidate function not viable: no known conversion from 'std::__1::string' (aka 'basic_string<char,
char_traits, allocator >') to 'char *' for 1st argument
So let's break it down:
1- if(isPalindrome(s)){
That's the line that failed compiling. The line has an if statement, a call to the isPalindrome function, and a reference to variable s. It also has some C syntax related to those, ( ( )){. The error could be in any of those. You do have an arrow to the isPalindrome function, so that's our best bet, but not necessarily the root cause yet.
2- palindrome.cpp:4:5:
That's an offending line (or at least, a line related to your issue). What this line does,
int isPalindrome(char* s){
is just declare a function. So now we know the issue is at least related to your function declaration, confirming the suspicion above.
2- candidate function not viable:
this goes a bit more detail into what the problem with that function is.
Each function call has to be matched to a function declaration. C++ accepts (function overloading)[https://en.wikipedia.org/wiki/Function_overloading], so given a function call, the compiler will find all "candidate" functions, that is, those that have a matching name. Between those, the compiler will look at certain hints, such as the types you're passing in, to determine which implementation to use.
The error here declares that there is no viable function. So there was no function that could be matched to the call you're making.
3- *no known conversion from 'std::__1::string' [...] to 'char ' for 1st argument:
Now this is the remaining piece we need. The compiler tells you that in the best candidate function it found, for the first (and only) argument, there is a type mismatch. The function expects a char *, but the argument being used in your call can't be converted to a char *. The argument you're passing is of type std::string, and that can't be converted to a char * automatically.
There are several ways to fix this, but the easiest route is to change your types so that either the variable you pass in is a char *, or the function you're defining expects the type you're passing in, that is, std::string.
As someone mentioned above, one way to achieve this, among several others, is to just add s.c_str() to your function call, instead of purely passing in s. That is a manual conversion from std::string to char *.
In general though, converting types with manual calls isn't a good solution from a performance or maintainability standpoint. You'd be better off just reimplementing either your function or your input reading to use the same type throughout, be it std::string or char *.

How to print out the first element of a const string?

How to print out the first element of a const string?
I tried to do std::cout << path[0] << std::endl; on CLion
but path[0] does not work and the IDE would warn.
CLion warns that
Cannot assign to return value because function 'operator[]' returns a const value.
type print(const std::string &path){}
You can use
std::string::at
It can be used to extract characters by characters from a given string.
Consider an example
#include <stdio.h>
#include<iostream>
using namespace std;
int main()
{
string str = "goodday";
cout << str.at(0);
return 0;
}
Hope this will help you.
First of all you can ignore the warning sometimes the compiler complains about unnecessary things, secondly do not do the following:
type print(const std::string &path){}
Dangerous, first of all Passing a string as a reference?? Think about it from the compilers point of view, the string is const, each time you use the += you are actually create a new string. But if you use the & with the string you are telling the compiler that you are planning to modify the string object which has type const..... Use string path as a parameter but never, ever use string& path......

Comparing element in string with length-1 string in C++

I am sorry for the simple question, but I cannot understand why this simple program does not work.
What is a[0] supposed to be other than "a"?
#include <iostream>
using namespace std;
int main(){
string a = "abcd";
string b = "a";
if (a[0]==b){//<------problem here
cout << a << endl;
}
return 0;
}
which returns the error
no match for ‘operator==’ (operand types are ‘char’ and ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’)
or simply using string c=a[0]; returns the error:
conversion from ‘char’ to non-scalar type ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’ requested
PS: after trying a few things, I can get it to work if I compare a[0]==b[0] or assign c[0]=a[0] because those are now definitely the same type, but I still would like to know what the standard and/or fastest way to carry out a comparison of a substring with another string in C++ is.
You should use std::string::find to find substrings. Using the subscript operator on string returns a single character (scalar), not a string (vector, non-scalar); therefore, they are not the same type and there is no defined comparison.
You can can also use std::string::substr to select a substring which you can directly compare against another string.
Example
#include <iostream>
#include <string>
int
main() {
std::string a = "abcd";
std::string b = "a";
if (a.find(b) != std::string::npos) {
std::cout << a << "\n";
}
if (a.substr(0, 1) == b) {
std::cout << a << "\n";
}
return 0;
}
References
http://en.cppreference.com/w/cpp/string/basic_string/find
http://en.cppreference.com/w/cpp/string/basic_string/substr
http://en.cppreference.com/w/cpp/string/basic_string
what is a[0] supposed to be other than "a"?
It is an 'a' not "a" and it is a char. You cannot compare a char to a string because they are different types. But what you can do is extract a substring from your string that is the length of 1 character:
if (a.substr(0,1)==b)...
Then you will be comparing "a" to "a" because .substr returns a string not a char, even if the length is 1.
Also don't forget to #include <string> if you are working with std::string.
a[0] is a character, which has the value 'a', whereas b is a string, which has a different type. This will work if an operator ==(char, string) is defined (or some variant with const's and/or ref's) but there isn't, at least in the C++ standard, so the compilation should fail. The clang compiler even gives the helpful message,
invalid operands to binary expression ('int' and 'string'...
which indicates that you're comparing different types.
Try changing it to compare a[0] and b[0]. The bracket operator is defined for strings, and returns a character, so you can compare them that way.
edit: This may look as if it doesn't answer the question. It does answer the original question; the OP changed the entirety of the question after the fact (and someone added a corresponding answer) but the original question is still there in the first paragraph. I'll delete the answer if moderators want.

Passing a string to file.open();

I am used to higher level languages (java, python etc.), where this is dead obvious. I am trying to pass a string the user inputs to cin, the name of a file to open. There appears to be some sort of pointer madness error, and my code will not compile.
I deleted some of my code to make it more clear.
#include <iostream>
#include <fstream>
using namespace std;
string hash(string filename);
int main(){
cout << "Please input a file name to hash\n";
string filename;
cin >> filename;
cout <<hash(filename);
return 0;
}
string hash(string filename){
file.open(filename);
if(file.is_open()){
file.close();
}
return returnval;
}
Here is the compile time error.
<code>
$ g++ md5.cpp
md5.cpp: In function ‘std::string hash(std::string)’:
md5.cpp:22: error: no matching function for call to ‘std::basic_ifstream<char, std::char_traits<char> >::open(std::string&)’
/usr/include/c++/4.2.1/fstream:518: note: candidates are: void std::basic_ifstream<_CharT, _Traits>::open(const char*, std::_Ios_Openmode) [with _CharT = char, _Traits = std::char_traits<char>]
</code>
(I know that there are libraries for md5 hashes, but I am trying to learn about how the hash works, and eventually hash collision)
open() takes a C-style string. Use std::string::c_str() to get this:
file.open (filename.c_str());
In order to use just a string, as pointed out below, you'll need to use a compiler with C++11 support, as the overload was added for C++11.
The reason it's not like Java etc. is that it came from C. Classes didn't exist in C (well, not nearly as well as they do in C++), let alone a String class. In order for C++ to provide a string class and keep compatibility, they need to be different things, and the class provides a conversion constructor for const char * -> std::string, as well as c_str() to go the other way.
Consider passing the argument (and maybe the return too) as const std::string & as well; no unnecessary copies. The optimization would probably catch those, but it's always good to do.

In C++, I thought you could do "string times 2" = stringstring?

I'm trying to figure out how to print a string several times. I'm getting errors. I just tried the line:
cout<<"This is a string. "*2;
I expected the output: "This is a string. This is a string.", but I didn't get that. Is there anything wrong with this line? If not, here's the entire program:
#include <iostream>
using namespace std;
int main()
{
cout<<"This is a string. "*2;
cin.get();
return 0;
}
My compiler isn't open because I am doing virus scans, so I can't give the error message. But given the relative simplicity of this code for this website, I'm hoping someone will know if I am doing anything wrong by simply looking.
Thank you for your feedback.
If you switch to std::string, you can define this operation yourself:
std::string operator*(std::string const &s, size_t n)
{
std::string r; // empty string
r.reserve(n * s.size());
for (size_t i=0; i<n; i++)
r += s;
return r;
}
If you try
std::cout << (std::string("foo") * 3) << std::endl
you'll find it prints foofoofoo. (But "foo" * 3 is still not permitted.)
There is an operator+() defined for std::string, so that string + string gives stringstring, but there is no operator*().
You could do:
#include <iostream>
#include <string>
using namespace std;
int main()
{
std::string str = "This is a string. ";
cout << str+str;
cin.get();
return 0;
}
As the other answers pointed there's no multiplication operation defined for strings in C++ regardless of their 'flavor' (char arrays or std::string). So you're left with implementing it yourself.
One of the simplest solutions available is to use the std::fill_n algorithm:
#include <iostream> // for std::cout & std::endl
#include <sstream> // for std::stringstream
#include <algorithm> // for std::fill_n
#include <iterator> // for std::ostream_iterator
// if you just need to write it to std::cout
std::fill_n( std::ostream_iterator< const char* >( std::cout ), 2, "This is a string. " );
std::cout << std::endl;
// if you need the result as a std::string (directly)
// or a const char* (via std::string' c_str())
std::stringstream ss;
std::fill_n( std::ostream_iterator< const char* >( ss ), 2, "This is a string. " );
std::cout << ss.str();
std::cout << std::endl;
Indeed, your code is wrong.
C++ compilers treat a sequence of characters enclosed in " as a array of characters (which can be multibyte or singlebyte, depending on your compiler and configuration).
So, your code is the same as:
char str[19] = "This is a string. ";
cout<<str * 2;
Now, if you check the second line of the above snippet, you'll clearly spot something wrong. Is this code multiplying an array by two? should pop in your mind. What is the definition of multiplying an array by two? None good.
Furthermore, usually when dealing with arrays, C++ compilers treat the array variable as a pointer to the first address of the array. So:
char str[19] = "This is a string. ";
cout<<0xFF001234 * 2;
Which may or may not compile. If it does, you code will output a number which is the double of the address of your array in memory.
That's not to say you simply can't multiply a string. You can't multiply C++ strings, but you can, with OOP, create your own string that support multiplication. The reason you will need to do that yourself is that even std strings (std::string) doesn't have a definition for multiplication. After all, we could argue that a string multiplication could do different things than your expected behavior.
In fact, if need be, I'd write a member function that duplicated my string, which would have a more friendly name that would inform and reader of its purpose. Using non-standard ways to do a certain thing will ultimately lead to unreadable code.
Well, ideally, you would use a loop to do that in C++. Check for/while/do-while methods.
#include <iostream>
#include <string>
using namespace std;
int main()
{
int count;
for (count = 0; count < 5; count++)
{
//repeating this 5 times
cout << "This is a string. ";
}
return 0;
}
Outputs:
This is a string. This is a string. This is a string. This is a string. This is a string.
Hey there, I'm not sure that that would compile. (I know that would not be valid in c# without a cast, and even then you still would not receive the desired output.)
Here would be a good example of what you are trying to accomplish. The OP is using a char instead of a string, but will essentially function the same with a string.
Give this a whirl:
Multiply char by integer (c++)
cout<<"This is a string. "*2;
you want to twice your output. Compiler is machine not a human. It understanding like expression and your expression is wrong and generate an error .
error: invalid operands of types
'const char [20]' and 'int' to binary
'operator*'