2

I'm writing my own string class StringEx in c++ (don't worry, just for exercise) but I'm failing at creating an instance of my class by assigning a string to it:

StringEx string1 = StringEx("test"); // works fine
StringEx string2 = "test"; // doesn't work

string string3 = "test";
string1 = string3; // also works fine

I overloaded the assignment operator so it can handle with std::string but I have to create an object of StringEx first.

How can I create a new object of StringEx by assigning a string to it? Is it even possible to get c++ handling every "string" as an object of my StringEx class?

This is my StringEx.h which works now

#ifndef STRINGEX_H
#define STRINGEX_H


#include <iostream>
#include <string>
#include <vector>
using namespace std; //simplyfying for now

class StringEx
{
private:
    vector<char> text;
public:
    StringEx();
    StringEx(string);
    StringEx(const char*);  // had to add this
    StringEx(vector<char>);

    int size() const;
    int length() const;
    char at(int) const;

    void append(const string&);
    void append(const StringEx&);
    void append(const char*);  // had to add this

    StringEx operator+(const string&);
    StringEx operator+(const StringEx&);
    StringEx operator+(const char*);  // had to add this too

    StringEx operator=(const string&);
    StringEx operator=(const StringEx&);
    StringEx operator=(const char*);  // had to add this too

    StringEx operator+=(const string&);
    StringEx operator+=(const StringEx&);
    StringEx operator+=(const char*);  // had to add this too

    friend ostream& operator<<(ostream&, const StringEx&);
};

#endif // STRINGEX_H
SimonH
  • 1,385
  • 15
  • 35
  • This is called initialization (more precisely, copy-initialization), not assignment. Assignment is when the object was already previously constructed (like in your last example). – interjay Sep 02 '15 at 08:57
  • Strangely enough: This code compiles just fine with VS2015 – Simon Kraemer Sep 02 '15 at 09:09
  • You've already got some answers, but you really should show the declaration of your class's constructors, copy constructors and copy assignments. – Fabio says Reinstate Monica Sep 02 '15 at 09:15
  • @SimonKraemer MSVC has never been a paragon of standards compliance. – TartanLlama Sep 02 '15 at 09:18
  • @TartanLlama Totally agree with you. There was just a case were the behaviour of MSVC was pretty strange in a special case of using templates and dependent types. After all it looks like the problem is that MSVC14 (VS2015) still doesn't support two-phased-name-lookup which is part of the standard since '99 or '03 – Simon Kraemer Sep 02 '15 at 09:22
  • 1
    @LPrulzcrossover Your edit shows the `StringEx.h` that caused the error, or the `StringEx.h` that works now? Please edit your question and explain what you are showing. – Simon Kraemer Sep 02 '15 at 09:24
  • that's the version that works now – SimonH Sep 02 '15 at 11:13
  • Actually the question should contain the version that *doesn't* work. As it looks right now, you have `StringEx (const char*);` and people are suggesting to add it, which is odd. Your question should contain the original version of the code, the one that gave the problems described in the question. If you want to show how you fixed it, I would add a paragraph called "EDIT" and put the modified code there, explaining that it is the updated version and that now it works. – Fabio says Reinstate Monica Sep 02 '15 at 11:28

3 Answers3

7

A few precisions:

StringEx string1 = StringEx("test"); // works fine

This use the copy-constructor, i.e. StringEx(const StringEx& other);

StringEx string2 = "test"; // doesn't work

This tries to use a constructor with the following signature: StringEx(const char* str);

Finally, those two lines:

string string3 = "test";
string1 = string3; // also works fine

create an std::string from a const char*, which the standard library defines, and then use the copy-assignment operator overloaded for std::string that you seem to have defined correctly, i.e. StringEx& operator=(const std::string& other).

The key point here is that this statement:

Type myVar = something;

is not an assignement, it's an declaration and initialisation of a variable which uses a constructor, not the copy-assignment operator.

In your case, you're just missing a constructor that takes a const char* as parameter.

JBL
  • 12,588
  • 4
  • 53
  • 84
  • The original code can be compiled with MSVC14/VS2015 and works just fine. Even though the IDE shows an error. – Simon Kraemer Sep 02 '15 at 09:15
  • Thanks, works now! Is it possible to get c++ handling every `const char*` as a `StringEx`? In order to get i.e. `cout << "hello" + "world";` work. – SimonH Sep 02 '15 at 09:15
  • @LPrulzcrossover You can't implicitly (well, maybe you could in a very ugly way that I'm not aware of). Why would you want that anyway? That line can work with a proper overload of `operator+` for two `const char*` that returns an `std::string` for example. – JBL Sep 02 '15 at 09:25
  • Is it even possible to overload `operator+` for two `const char*`? Considering [this](http://stackoverflow.com/questions/5533085/overload-operator-char-ch1-char-ch2) it seems like the answer is no, or how would you do that? – SimonH Sep 02 '15 at 09:38
  • 1
    Should've checked before, it's actually not possible. C++ Standard at §13.5.6 specifies that at least one of the parameters type must be a class, a reference to a class, an enumeration, or a reference to an enumeration, when overloading binary operators. My bad. – JBL Sep 02 '15 at 09:47
4

I assume that you have a non-explicit constructor of the form

StringEx (const std::string&);

or similar.

String literals are not of type std::string. "test" is of type const char[5]. std::string has a non-explicit constructor accepting a const char*, so your two calls look like this (not taking copy elision into account):

//implicitly convert "test" to temporary std::string
//construct temporary StringEx with temporary std::string
//copy-construct StringEx with temporary
StringEx string1 = StringEx("test"); 

//no StringEx constructor taking const char*
//two conversions necessary to make "test" into a StringEx
//invalid
StringEx string2 = "test";

An easy fix for this is to add a constructor taking a const char* to StringEx:

StringEx (const char*);

Alternatively you could just use direct initialization:

//only one conversion needed
StringEx string2 ("test");
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
3

TLDR: The compiler won't autoresolve if 2 "casts" are necessary. In this case const char* to std::string to StringEx


StringEx string1 = StringEx("test"); // works fine > This calls the constructor explicitly and therefore only one conversion must be done: const char* to std::string.

StringEx string2 = "test"; // doesn't work > This on the other hand is not clear. Do you want to cast const char* to std::string and use the StringEx(const std::string&)constructor or use some other intermediate class?

What you need is another constructor accepting const char* as parameter.

BTW:

StringEx string4 = std::string("test"); //Also works
Simon Kraemer
  • 5,700
  • 1
  • 19
  • 49