0

EDIT: Compiler version fixed.

I'm trying out the new features of c++11 although I have Ubuntu 12.04 which includes gcc 4.6.3, thus only supporting c++0x. I have a general understanding problem with the following example class and it's constructors, assign operators and other operators.

class exception : public std::exception {
  public:
    exception(string& inMessage) throw() : message(inMessage) {
      std::cout << "exception(string& inMessage): '" << message << "'" << std::endl;
    }
    exception(string&& inMessage) throw() : message(std::move(inMessage)) {
      std::cout << "exception(string&& inMessage): '" << message << "'" << std::endl;
    }
    ~exception() throw() { }
    exception& operator =(string&& inMessage) {
      std::swap(message, inMessage);
      std::cout << "operator =(string&& inMessage): '" << message << "'" << std::endl;
      return *this;
    }
    exception& operator =(string& inMessage) {
      message = inMessage;
      std::cout << "operator =(string& inMessage): '" << message << "'" << std::endl;
      return *this;
    }
    exception& operator <<(string&& inMessage) {
      message += inMessage;
      std::cout << "operator <<(string&& inMessage): '" << message << "'" << std::endl;
      return *this;
    }
    exception& operator <<(string& inMessage) {
      message += inMessage;
      std::cout << "operator <<(string& inMessage): '" << message << "'" << std::endl;
      return *this;
    }
    char const* what() const throw() {
      return message.c_str();
    }
  private:
    string message;
};

I'm now trying to invoke all the above constructors and operators with the following

// constructors:
exception e1("This is the move constructor"); // move construct

exception e2 = "This is again the move constructor"; // move construct

string s("This is a lvalue string");
exception e3(s); // copy construct

// assignment:
e2 = "This is the move assignment"; // move assign

e2 = s; // copy assign

// operator <<:
e3 << "This is the rvalue reference operator >>"; // rvalue ref

e3 << s; // lvalue ref

e3 << std::move(s); // forced rvalue ref

As I found out, this won't compile because of the line

exception e2 = "This is again the move constructor"; // move construct

which seems to be an illegal move constructor invoke. As I understand, the char const[] is implicitly converted to string&& just as in

e3 << "This is the rvalue reference operator >>"; // rvalue ref

or

e2 = "This is the move assignment"; // move assign

Why does the standard not allow this?

The error I'm getting is this:

main.cpp:40:18: error: conversion from ‘const char [33]’ to non-scalar type ‘exception’ requested

I can easily solve this error by changing the line into

exception e2 = string("This is again the move constructor"); // move construct
poljpocket
  • 33
  • 6

2 Answers2

2

The reason for this is that in order to create an exception from your const char[] message, the compiler would have to invoke two implicit conversions (one from const char[] to string, and thence to an exception), but the C++ standard (C++11 included) only allows one.

See this question for more detail including chapter and verse from the C++ standard.

Community
  • 1
  • 1
Edward
  • 6,964
  • 2
  • 29
  • 55
1
exception e2 = "This is again the move constructor"; // move construct

First of all, the code you've shown doesn't have a move constructor. A move constructor would be one that accepts exception&&. A default move constructor isn't being generated for you, because you've explicitly declared a destructor.

What the line above tries to do is invoke your default copy constructor. To do this, it has to convert from a string-literal to an exception, which isn't possible in a single step.

exception e2 = string("This is again the move constructor"); // move construct

Now this only requires one conversion. But it will call your default copy constructor instead of the string&& constructor.

Daan
  • 484
  • 4
  • 13
  • Talking about move constructors is somewhat wrong, yes. It's more a constructor accepting a rvalue reference string and lvalue reference string. The same applies to the assignment operator. There's the rval ref and the lval ref. My question is why the implicit conversion to string&& isn't allowed in this very case. – poljpocket May 02 '14 at 10:46