Home > Back-end >  Is it possible to have a function-try-block per member initialiser?
Is it possible to have a function-try-block per member initialiser?

Time:07-17

During the member initialisation of a class with multiple members, it seems desirable to be able to catch an exception generated by any specific member initialiser, to wrap in additional context for rethrowing, but the syntax of a function-try-block doesn't appear to accomodate that.

#include <stdexcept>
#include <string>
#include <sstream>

using namespace std::literals::string_literals;

[[noreturn]]
int thrower() { throw std::runtime_error("unconditional throw"s); }
int nonThrower() { return 3; }

class C {
    int x;
    int y;

    public:
    C();
};

class XError : public std::runtime_error {
    public:
    XError(const std::string& what) : std::runtime_error((std::stringstream() << "xerror: "s << what).str()) {};
};

class YError : public std::runtime_error {
    public:
    YError(const std::string& what) : std::runtime_error((std::stringstream() << "yerror: "s << what).str()) {};
};

C::C() try:
    x(nonThrower()),
    y(thrower()) {}
    catch(const std::exception& e) { /* ... */ }

In the above trivial example, on the final line, I would very much like to be able to throw XError() if the exception occurs in initialisation of .x, and YError() if the exception occurs in initialisation of .y.

Ideally I'd like to be able to do something like

// -std=c  3000
C::C():
    try: x(nonThrower()) catch(const std::exception& e) { throw XError(e.what()); },
    try: y(thrower()) catch(const std::exception& e) { throw YError(e.what()); } {}

But it seems my only option is to write separate functions per initialiser member which wrap the exceptions themselves, then use those in the member initialisers. Given how ghastly member initialiser syntax is, this will probably read better, but it's less compact and more non-linear, which is less than ideal. For completeness:

int makeX() {
    try { return nonThrower(); }
    catch(const std::exception& e) { throw XError(e.what()); }
}

int makeY() {
    try { return thrower(); }
    catch(const std::exception& e) { throw YError(e.what()); }
}

C::C():
    x(makeX()),
    y(makeY()) {}

Please excuse any antipatterns or mistakes in my C . I am both very new to the language and not as smart as you might hope me to be.

CodePudding user response:

Is it possible to have a function-try-block per member initialiser?

No, that is not possible.

Sidebar: it seems like you're overusing and/or overthinking exceptions. Most people don't write much exception-handling code, because most programs are fine with just terminating if an exception is thrown, in most places. Of course there are exceptions to this rule, but if you're new to C and you're getting hung up on this, you should probably revisit your approach and not make your program so reliant on fine-grained exception handling.

CodePudding user response:

It's not possible, but if you want to go down the exception route you can write function wrappers:

template<typename Exn, typename T>
T catch_with(T (*fn)()) // or, std::function<T()> fn
{
    try { return fn(); }
    catch(const std::exception& e) { throw Exn(e.what()); }
}


C::C():
    x(catch_with<XError>(nonThrower)),
    y(catch_with<YError>(thrower) {}
  • Related