5

At the top of my program, I have an exception handler.
It looks something like this:

try{
    //majority of program
}
catch(...){
   Handle_All_Exceptions();
}


void Handle_All_Exceptions(){
   try{throw;}
   catch(TypeA const& e){Handle(e)       ;}
   catch(TypeB const& e){Handle(e)       ;}
   catch(TypeC const& e){Handle(e)       ;}
   catch(TypeD const& e){Handle(e)       ;}
   catch(...)           {Handle_Unknown();}

}

void Handle(TypeA const& e){
    //...
}
void Handle(TypeB const& e){
    //...
}
void Handle(TypeC const& e){
    //...
}
void Handle(TypeD const& e){
    //...
}
void Handle_Unknown(){
    //...
}

As I obtain more an more exception types,
I'd like to take a more generic approach.
How can I apply generic programming to the Handle_All_Exceptions function?


Would something like this be possible in newer versions of C++?

catch(auto e){Handle(e)};
catch(...){Handle_Unknown();}
4

1 に答える 1

0

言語とその例外システムに大幅な変更を加えなければ、それは不可能です。catch-clause ハンドラーと関数パラメーターは構文的には似ているように見えますが、動作はまったく異なります。検討:

struct up {};
struct down { constexpr down(up) noexcept {} };

void func(down const&) {}
void except()
{
    try {
        throw up {};
    } catch(down const&) {}
}

int main()
{
    func(up {}); // fine
    except();    // exception `up` escapes
}

Coliru

言い換えると、down const&パラメータは に変換可能なものなら何でも受け入れますがdown、ハンドラは 型またはから明確に派生down const&した型の例外オブジェクトにバインドします。downdown

ここでの大きな違いは、「変換可能」という形式の関係がさまざまな形式を取ることができることです。この例では、変換コンストラクターを使用しましたが、代わりに 内で変換演算子を使用することもできましたup。一方、「is (公に、明確に) 派生したもの」は、1 つの直接的な方法でのみ、プログラム全体で正確に 1 つの場所 (派生型が定義されている場所) でのみオプトインできます。これは、個別のコンパイルを考慮する場合に重要です。次のプログラムを検討してください。

// a.cpp

// defined in b.cpp
void throws() noexcept(false);

template<typename X>
concept bool Fooable = requires(X x) { x.foo(); }

int main()
{
    try {
      throws();

      // imaginary syntax for catching models of a concept
    } catch(Fooable const&) {}
}

// b.cpp

// defined in c.cpp
struct other;

struct model {
    void foo() {}
    other* foo(int) { return nullptr; }
    void bar() {}
};

void throws() noexcept(false)
{ throw model {}; }

// c.cpp omitted

がコンパイルされると、コンパイラは、「投げているオブジェクトは可能ですか?」という質問をするb.cppことを知る方法がありません。それにもかかわらず、その事実を悲観的に記録する必要がありますか (現在の規則の下では、「is-derived from」関係があれば、どこかに記録されます)。完全なプログラムでは必要ないのに、ができるという事実も記録する必要がありますか? 代わりにテストされた場合はどうなりますか?表現が意味を成すように定義されているとしたら、それはどこで、いつ、どのように記録されるでしょうか? どのように とが別々に定義されており、それぞれがお互いについて (あまり) 知らないことに注意してください。a.cppx.foo()modelx.bar()Fooablex.foo(0)->baz()othermodelother

確かにあなたが求めていることは不可能ではありませんが、私たちが現在持っているシステムとはかなり異なって見え、機能する前に多くの努力が必要になることに同意できることを願っています. 現在のルールでは、例外に対するジェネリック プログラミングは限界に達しており、昔ながらのクラス階層を使用することが最も抵抗の少ない方法です。

于 2015-09-13T17:54:23.863 に答える