default argument declaration :why a default string parameter must be const [duplicate] - c++

This question already has answers here:
How come a non-const reference cannot bind to a temporary object?
(11 answers)
Closed 7 years ago.
what is the reason of having to put that const on the last parameter of my function(it has default argument declaration) if it was not default, it would not need that const
string make_plural(string &word, size_t c, const string &ending = "s")
{
return c > 1 ? word + ending : word;
}
the error is : 'default argument' : cannot convert from 'const char [2]' to 'std::string &'
but i cannot understand why. can any body explain please.

I have found out the answer myself.
we have to put that const because string literals are const and in the code we were initializing a const string to a plain reference which is in error.
to make it clear look below:
string &r="some string";
is in error but
const string &r="some string";
is valid
and if :
string make_plural(string &word, size_t c,const string &ending = "s")
{
return c > 1 ? word + ending : word;
}
if the first parameter was a plain reference then the call could be:
string str = "thing";
cout << make_plural(str,2) << endl;
but if you want the call to be:
cout << make_plural("thing",2) << endl;
you have to add const for the first parameter as follows
string make_plural(const string &word, size_t cnt,const string &ending = "s")
{
return cnt > 1 ? word + ending : word;
}
reasons and rules to initializing parameter are the same as variables so:
plain references cannot be initialized by const values such as a string literals that are consts.

Related

Getting error while initializing string with string character array? [duplicate]

This question already has answers here:
no viable conversion from 'value_type' (aka 'char') to 'string' (aka 'basic_string<char, char_traits<char>, allocator<char> >')
(1 answer)
Initializing a string with a single character
(1 answer)
Closed 1 year ago.
I'm trying to initialize this string s1 but Idk why I'm getting this error, This may be due to s[0] is character but why everything turns fine when I initialize and declare same string s1 but in diffrent lines, one after another.
#include <bits/stdc++.h>
int main()
{
std::string s = "text";
std::string s1 = s[0];
std::cout << s1;
}
Error:
error: conversion from '__gnu_cxx::__alloc_traits<std::allocator<char>, char>::value_type'
{aka 'char'} to non-scalar type 'std::__cxx11::string' {aka
'std::__cxx11::basic_string<char>'} requested
std::string s1 = s[0];
^
This is working fine:
#include <bits/stdc++.h>
int main()
{
std::string s = "text";
std::string s1;
s1 = s[0];
std::cout << s1;
}
There's no constructor for char. There's a copy assignignment, which works for the second snippet.
However, you can write either like
std::string s1 ( 1, s[0] );
std::string s1 = s[0]; is initialization, it doesn't work because std::string doesn't have any constructor taking a single char.
s1 = s[0]; is assignment, it works because std::string has a operator= taking a single char.
If we take a look at the documentation, we can see that
std::string has no constructor that takes a char type - cppreference.com
It does have an overload for the operator= that can take a
char - cppreference.com
[The copy assignment that takes a char] replaces the contents with
character ch as if by assign(std::addressof(ch), 1)
As to why, consider the fact that the std::string already has so called fill-constructor, string s(n, val), that takes an initial value val and fills the string with n copies of it. So there's no need to have special case for n == 1:
std::string s1 = "text";
std::string s2(1, s[0]); // One char of value s[0]
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s = "text";
string s1;
s1 = s;
cout << s1;
}
the code should work now.

Please explain char* return type in C++ [duplicate]

This question already has answers here:
cout << with char* argument prints string, not pointer value
(6 answers)
Closed 2 years ago.
I have written a simple C++ code, and its working fine. But I don't know how it is working. I am just replacing "l" with "r" using myfun().
The return type of myfun() is char*. If I am returning &(str[0]), that is, only the address of the first element of the array, then why is it printing the complete string "herloworld"? Please explain what return &(str[0]); is doing.
#include <iostream>
using namespace std;
char* myfun(char str[])
{
str[2] = 'r';
return &(str[0]);
}
int main()
{
char str[] = "helloworld";
char* word;
word = myfun(str);
cout << word;
}
The operator << is overloaded for the type char * such a way that it expects that the used pointer of the type char * points to the first character of a string.
So the operator outputs all characters of the passed string until the zero character '\0' is encountered.
Also pay attention to that arrays used in expressions with rare exceptions are converted to pointers to their first elements.
So this call
word = myfun(str);
is equivalent to
word = myfun( &str[0]);
On the other hand, a function parameter having an array type is implicitly adjusted to pointer to the element type.
So this function declaration
char* myfun(char str[]);
is equivalent to the following declaration
char* myfun(char *str);
The both declarations declare the same one function.
And within the function instead of this return statement
return &(str[0]);
you could write
return str;
Correspondingly in main you could write
cout << myfun(str);
without declaring and using the intermediate pointer word.

Why I can't assign string::back to string?

I write a simple program:
Get last character of string1 and assign it to string2.
It's like:
#include<iostream>
#include<string>
int main(int argc, char const *argv[])
{
std::string s1 = "abc!";
std::string s2 = s1.back();
std::cout << s1;
return 0;
}
However, I get a compile error:
conversion from ‘__gnu_cxx::__alloc_traits<std::allocator<char> >::value_type {aka char}’ to non-scalar type ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’ requested
I don't know this error exactly means.
It's seems like some type conversion error occur.
But the return value of string::back should be char, right?
Why I can't assign it to another string?
And how I can give last character of s1 to s2?
It's because std::string does not have an implicit constructor which takes just a single character parameter, that's why conversion from char to std::string fails. Instead you can use:
// 1. Constructor with length + char
std::string s2(1, s1.back());
// 2. Constructor which takes an std::initializer_list<char>
std::string s2{s1.back()};
A string is a collection of characters, the back of a string is a character (i.e., just an element of the collection), not a string.
You can achieve what you want by using the following constructor overload of std::string:
std::string s2(1, s1.back());
That is, construct s2 as a one-character-length string with the value s1.back().
Hope you are trying to create a new string s2 out of the last character of string s1.
You can achieve that using the solution below:
#include<iostream>
#include<string>
int main()
{
std::string s1 = "abc!";
std::string s2;
s2 = s1.back();
std::cout << s1;
std::cout << s2;
return 0;
}

C++ Literal string and const string reference argument [duplicate]

This question already has answers here:
String literal matches bool overload instead of std::string
(4 answers)
Closed 7 years ago.
I have two overload function with const std::string& and bool respectively. I am now calling the function with literal string. The bool version is called. This is a bit weird, and it is really a pitfall.
Can anyone explain why?
See the code below. The output is
Write == 1
#include <iostream>
#include <string>
void write(const std::string& name_) {
std::cout << "Write == " << name_ << std::endl;
}
void write(bool name_) {
std::cout << "Write == " << name_ << std::endl;
}
int main()
{
write("data");
}
The issue is that your argument to write is not a value of type std::string (it is not a literal of std::string) but a character array.
Unfortunately, and I agree with you that it is a pitfall, the rules of the overload resolution will pick the conversion of array to boolean over conversion to const reference to string.
Mind you, there are in C++ 11 actual std::string literals, I won't go into the details here.
What fixes the overload is to convert explicitly to std::string:
write(std::string("data")) will do the right thing.
Prevent this issue in the future. It is indeed a pitfall.

Unexpected problems concatenating strings

I'm trying to concatenate strings using +, but there is some weird stuff going on. Here is my "Grade" class I have for a class project:
#pragma once
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Grade {
private:
string className;
string student;
string letter;
public:
Grade(string c, string s, string l) : className(c), student(s), letter(l) {}
string getLetterGrade() const { return letter; }
string getClassName() const { return className; }
string getStudent() const { return student; }
void setLetterGrade(string l) { letter = l; return;}
void setClassName(string c) { className = c; return;}
void setStudnet(string s) { student = s; return;}
string toString() const { string output = "hello"+student; return output; }
};
Obviously, the toString() method isn't currently what I want it to be.
If I run the toString() as above, I get "hello529173860" out, as expected. However, if I change the line to:
string toString() const { string output = student+"hello"; return output; }
then the output is "hello3860". This isn't just putting the hello string on the front, but its replacing characters from the student string in the process... somehow?
Furthermore, if I try to use:
string toString() const { string output = "hello"+" world"; return output; }
I get an error:
Grade.h: In member function ‘std::string Grade::toString() const’:
Grade.h:29:53: error: invalid operands of types ‘const char [6]’ and ‘const char [7]’ to binary ‘operator+’
string toString() const { string output = "hello"+" world"; return output; }
^
I'm really at a loss for what it going on here... especially since I have done string concatenation earlier in the program without issue.
What I would like is to output something like:
"student+[some white space]+letter+[some white space]+className"
A std::string can be added to anything (another std::string, double-quoted string literal, char) and provide intuitive results, but if you try to add a double-quoted string literal to another string literal or a char then it won't "work":
a string literal added to a char or other integral value will undergo Standard Conversion to a const char*, then any number added to the pointer will move along the literal that number of characters: if the offset isn't inside the string literal then you get undefined behaviour if you dereference (use) the resultant pointer,
two string literals just can't be added, even after decaying to two pointers, so you'll get a compile-time error.
Sometimes you will want to explicitly construct a std::string so that concatenation with other values works as you'd like: e.g. my_string = std::string("hello ") + my_const_char_ptr + '\n'.
Examples:
std::string s = "Hello";
s + " World"; // ok
"Hello " + s; // ok
"Hello " + "World"; // NOT ok - two string literals
s += " World"; // ok
s += " Goodbye " + "World"; // NOT ok - "+" evaluated before "+="
s += std::string(" Goodbye ") + "World"; // OK - right-hand-side no longer two literals
// BUT may be slower than two "s +="
The constant strings "hello" and "world" are nothing but compile time constants of type const char*. Just like you cannot add two int pointers:
int *p1, *p2;
p1+p1; // Error
You cannot add two (const) char* objects. This is against the C/C++ language rules. If you must concatenate two const-char-pointers, you can just place them together:
"hello" "world"
This technique is mainly useful if you use them along with macros. For example:
// Over simplified
#define ONE(_x) _x
#define TWO(_x) _X
ONE("This is") TWO(" concatenation")
If you are adding two (or more) runtime C-Strings, you must use strXXX functions (like strcat), or better use std::string.
There is no operator + for character arrays. So it is obvious that this code
string toString() const { string output = "hello"+" world"; return output; }
is invalid.
In this expression "hello"+" world" there are used two string literals that have the types correspondingly const char[6] and const char[7]. The operator + is not defined for arrays.
You could just write
string toString() const { return string( "hello" ) + " world"; }
In this case there is used the operator + overloaded for the class std::string. Declaration of the local variable input is redundant. So you could simplify the function even the following way
string toString() const { return "hello world"; }