1

I have some exceptions derived from std::exception or std::runtime_error. The only method is constructor explicit MyExceptionX(const char *text = "") : std::exception(text) {}. Are there ways to make this code simpler without use of macro?

class MyException1: public std::exception
{
public:
    explicit MyException1(const char *text = "") : std::exception(text) {}
};

class MyException2: public std::exception
{
public:
    explicit MyException2(const char *text = "") : std::exception(text) {}
};

class MyException3: public std::exception
{
public:
    explicit MyException3(const char *text = "") : std::exception(text) {}
};

//...
Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
Ufx
  • 2,595
  • 12
  • 44
  • 83

3 Answers3

7

There's no need to use class when everything is public. You can use struct instead. Also, you can inherit constructors:

struct MyException1: std::exception
{
    using std::exception::exception;
};

struct MyException2: std::exception
{
    using std::exception::exception;
};

struct MyException3: std::exception
{
    using std::exception::exception;
};

Also, if you really just need different types, you can do this:

template <int>
struct MyException : std::exception
{
    using std::exception::exception;
};


using MyException1 = MyException<1>;
using MyException2 = MyException<2>;
using MyException3 = MyException<3>;

You can use an enum instead of an int if you want more descriptive names.

Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
  • I like your suggestion but I usually use it with an `enum` like so: `enum class my_problems { no_money, no_love, no_sleep }; template struct my_exception : std::exception {};` Then you can say things like `my_exception` which I find very expressive. You might not need the `using` alias at all any more. – 5gon12eder Jan 24 '16 at 22:47
  • @5gon12eder: Agreed. I started to do it that way, but it ended up looking silly for this example: `enum class ExceptionId {one,two,three}`. – Vaughn Cato Jan 24 '16 at 22:48
  • I see what you mean. That's the problem with contrived examples. – 5gon12eder Jan 24 '16 at 22:50
  • @5gon12eder: I added a note about that. – Vaughn Cato Jan 24 '16 at 22:50
  • @vaughn-cato `struct MyException1 : public std::runtime_error { using std::runtime_error::runtime_error; };` `throw MyException1("error");` error C2440: '' : cannot convert from 'const char [6]' to 'MyException1' – Ufx Jan 24 '16 at 22:52
  • @Ufx: May be an issue with the compiler. I'm not seeing that: https://ideone.com/HNwHqO – Vaughn Cato Jan 24 '16 at 23:00
  • @vaughn-cato MSVC120. cannot convert from 'const char [6]' to 'MyException1'. No constructor could take the source type, or constructor overload resolution was ambiguous – Ufx Jan 24 '16 at 23:02
  • @Ufx: Looks like MSVC 12 didn't support inheriting constructors. – Vaughn Cato Jan 24 '16 at 23:05
  • @vaughn-cato are inheriting constructors in C++ standard? – Ufx Jan 24 '16 at 23:07
  • @Ufx Are you deriving from `std::exception` directly as shown in your question? It doesn't have a constructor that takes a message so you cannot inherit it. Derive from `std::runtime_error` (or some related `class`) instead. I guess it's this that was meant by “Is your code supposed to compile?” – 5gon12eder Jan 24 '16 at 23:10
  • Compiles in MSVC140. Doesn't in MSVC120 . – Ufx Jan 25 '16 at 18:49
0

You can be using the superclass' constructor. The following simplified code example does what you are looking for:

#include <iostream>

class A {
public:
  A(char* cText) {
    std::cout << cText << std::endl;
  }

  ~A() {
  }
};

class B : public A {
public:
  using A::A;

  ~B() {
  }
};

int main(int argc, char** argv) {
  B("Test");

  return 0;
}

Additionally, the using feature for inheriting constructors is only available when compiling with -std=c++11 or -std=gnu++11.

  • A better solution would be to not use `new` and `delete` at all. – juanchopanza Jan 24 '16 at 22:43
  • @BryanChen no, you don't. It works like a charm without making `~A()` virtual. Making it virtual actually *chages* what the effect of the polymorphism is w.r.t. what gets executed when deconstructing the class. Additionally, polymorphism of the destructor is not subject to OP's question. –  Jan 24 '16 at 22:43
  • @juanchopanza Acknowledged, I'll change that. Thanks. –  Jan 24 '16 at 22:45
0

The following compiles fine in my VisualStudio 2012:

template <const char *&text>
class MyException: public std::exception
{
public:
    virtual const char* what() const { return(text); }
};

const char *Ex1 = "Message1";
const char *Ex2 = "Message2";
const char *Ex3 = "Message3";

int _tmain(int argc, _TCHAR* argv[])
{
    throw MyException<Ex1>();
    throw MyException<Ex2>();
    throw MyException<Ex3>();
    return 0;
}

Unfortunately C++ does not allow using string literals in the throw statement itself. Details can be found here: String literals not allowed as non type template parameters.

Community
  • 1
  • 1
Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51