8

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.

6
  • 5
    I note that this builds just fine under VS2017. It is worth remembering that a string literal is not the same as a std::string. Commented Jun 10, 2017 at 12:21
  • Is that a full example? Any headers included? What is string in your case? Commented Jun 10, 2017 at 12:25
  • @Artur R. Czechowski - It is a full example (I added the headers). string should be std::string I guess. Commented Jun 10, 2017 at 12:33
  • 1
    Try adding a constructor for const char*. As @Artur R. Czechowski said, a std::string is not the same as a string literal. Commented Jun 10, 2017 at 12:37
  • 2
    @Rook MSVC has an extension to allow multiple implicit user-defined conversions. Cranking up the warning level should produce a diagnostic. Commented Jun 10, 2017 at 15:14

2 Answers 2

11

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) 
Sign up to request clarification or add additional context in comments.

6 Comments

So the one user-defined conversion requirement also applies to implicit conversions? Because otherwise const char[2] -> implicit const char* -> user-defined std::string, right?
@Rakete1111 (1) Yes, only one user-defined conversion is allowed in one implicit conversion sequence; (2) I can't get your intent, const char[2] -> const char* is not user-defined conversion but standard conversion which could be more than once.
Yes, that's exactly my point: If only 1 user defined conversion is allowed, then const char[2] -> const char* doesn't count, and std::string's constructor can be used (which is 1 user defined conversion). But why is it not allowed then?
@Rakete1111 That's because we need to convert const char[2] to CLS for copy initialization.
@Rakete1111 Yes, otherwise user-defined conversions would be able to be chained.
|
8
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.

2 Comments

You mean "[...] user defined conversion from (in case of d) char const[] [...]"? "5" can decay to const char*, but it is a const char[2].
@Rakete1111 there you go, I initially left decay out of the answer to keep it focussed on the conversions.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.