每个成员初始化器是否可以有一个函数尝试块?

Ada*_*nes 6 c++ member-initialization function-try-block

在具有多个成员的类的成员初始化期间,似乎希望能够捕获由任何特定成员初始化程序生成的异常,以包装在额外的上下文中以便重新抛出,但是函数 try 块的语法没有出现为了适应这一点。

#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) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

XError()在上面的简单示例中,在最后一行,如果异常发生在 的初始化中.x,并且YError()如果异常发生在 的初始化中,我非常希望能够抛出.y

理想情况下我希望能够做类似的事情

// -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()); } {}
Run Code Online (Sandbox Code Playgroud)

但似乎我唯一的选择是为每个初始化程序成员编写单独的函数,这些函数本身包装异常,然后在成员初始化程序中使用这些函数。考虑到成员初始化语法是多么可怕,这可能会读起来更好,但它不太紧凑,而且更非线性,这不太理想。为了完整性:

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()) {}
Run Code Online (Sandbox Code Playgroud)

请原谅我的 C++ 中的任何反模式或错误。我对这门语言很陌生,而且不像你希望的那样聪明。

Joh*_*nck 8

每个成员初始化器是否可以有一个函数尝试块?

不,那是不可能的。

侧边栏:看来您过度使用和/或过度思考异常。大多数人不会编写太多异常处理代码,因为大多数程序在大多数地方只要抛出异常就终止就可以了。当然,这条规则也有例外,但如果您是 C++ 新手并且对此很着迷,那么您可能应该重新审视您的方法,而不是让您的程序如此依赖于细粒度的异常处理。

  • 我并没有说不应该抛出异常。我说应该很少有异常捕获。如果出现错误以致您的程序抛出异常,那么在大多数程序中您也可以让它终止。但同样,您是 C++ 新手,首先关注其他方面,这是一个兔子洞,并不像您现在看起来那么重要。 (3认同)

mol*_*ilo 7

这是不可能的,但如果你想走异常路线,你可以编写函数包装器:

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) {}
Run Code Online (Sandbox Code Playgroud)