Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Construct an object with a string literal

I have the following class:

#include <iostream>
#include <string>

using namespace std;

class CLS
{
   int value;
   string str_value;

public:

    CLS(int param) { value = param; }

    CLS(string param)
    {
       str_value = param;
    }
};

int main()
{
    CLS a(2);
    CLS b = 3;
    CLS c("4");
    CLS d = "5";  // Error: invalid conversion from 'const char*' to 'int'
}

I searched for the reason why it is error with no luck.

Is it correct to construct with a string literal? if no, why? if yes, what is wrong with my code?

I am using gcc 5.3 with Code::Blocks 16.1.

like image 577
Kamal Zidan Avatar asked Jun 10 '17 12:06

Kamal Zidan


People also ask

Does string literal create object?

4. String Literal vs String Object. When we create a String object using the new() operator, it always creates a new object in heap memory. On the other hand, if we create an object using String literal syntax e.g. “Baeldung”, it may return an existing object from the String pool, if it already exists.

What is a string literal object?

String literals or constants are enclosed in double quotes "" or with @"". A string contains characters that are similar to character literals: plain characters, escape sequences, and universal characters. Here are some examples of String Literals − Hello, World" "Welcome, \

How do you make a string literal?

A "string literal" is a sequence of characters from the source character set enclosed in double quotation marks (" "). String literals are used to represent a sequence of characters which, taken together, form a null-terminated string. You must always prefix wide-string literals with the letter L.

What is an example of a string literal?

A string literal is a sequence of zero or more characters enclosed within single quotation marks. The following are examples of string literals: 'Hello, world!' 'He said, "Take it or leave it."'


2 Answers

At first, "4" is not std::string, it's const char[2]. Then

CLS c("4"); is direct initialization, the constructors of CLS will be examined for initializing c. CLS::CLS(string) is picked up here, because const char[] can be implicitly converted to std::string via user-defined conversion (i.e. by std::string::string(const char*)).

CLS d = "5"; is copy initialization,

(emphasis mine)

  • If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution.

That means user-defined conversion sequences is required to convert const char[2] to CLS. Even const char[] could be converted to std::string, and std::string could be converted to CLS, but only one user-defined conversion is allowed in one implicit conversion sequence. That's why it's rejected.

(emphasis mine)

Implicit conversion sequence consists of the following, in this order:

1) zero or one standard conversion sequence;
2) zero or one user-defined conversion;
3) zero or one standard conversion sequence.

BTW: If you change it to using std::string as the initializer expression explicitly it'll work fine. e.g.

CLS d = std::string{"5"};  // pass a temporary std::string constructed from "5" to the constructor of CLS

using namespace std::string_literals;
CLS d = "5"s;              // "5"s is a string literal of type std::string (supported from C++14)
like image 57
songyuanyao Avatar answered Oct 02 '22 20:10

songyuanyao


CLS a(2); 
CLS b = 3;
CLS c("4");
CLS d = "5";

aand c are initialised with direct initialisation. b and d on the other hand use copy initialisation.

The difference is that for copy initialisation the compiler searches for a (single) user defined conversion from (in case of d) char const * (this is a bit inaccurate, see end of answer) to CLS, whereas for direct initialisation all constructors are tried, where CLS(std::string) can be used​ because there's a conversion std::string(char const *) available.

Detail:

"5" is a (C) string literal. It's type is char const [2]. So first, a user defined conversion from that type to CLS is searched. Because none is found, the standard conversion from Type[N] to Type * (with Type = char const and N = 2) is applied, resulting in a char const *. Then the compiler tries to find a user defined conversion from that to CLS. Because it doesn't find one, and there are no more standard conversions it could try available, compilation fails.

like image 44
Daniel Jour Avatar answered Oct 02 '22 20:10

Daniel Jour