Search code examples
c++stringconstructorinitializationstring-literals

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.


Solution

  • 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)