3

Andrei Alexandrescu は、前回のC++ and Beyond で体系的なエラー処理に関する講演を行いました。私は Expected テンプレート パターンが好きで、これを Visual Studio 2010 に適合させました。これは、コンパイラがこれまでのところ拡張ユニオンをサポートしていないためです。そこで、すべてが機能することを確認する UnitTest を作成しました。そこで、スライスされた例外の検出が機能することを確認したいということになりました。しかし、そうではありませんでした。

ここに完全なコードを貼り付けたくなかったので、要点を減らしてみました。

#include <iostream>
#include <string>
#include <exception>
#include <typeinfo>

class MyException : public std::exception
{
public:
  MyException()
    : std::exception()
  {}
  virtual const char* what() const { return "I come from MyException"; }
};

void hereHappensTheFailure()
{
 throw MyException();
}

template <class E>
void detector(const E& exception) 
{
  if (typeid(exception) != typeid(E)) 
  {
    std::cout << "Exception was sliced" << std::endl;
  }
  else
  {
    std::cout << "Exception was not sliced" << std::endl;
  }
}

int main()
{
  try
  {
    hereHappensTheFailure();
  }
  catch (std::exception ex) // intentionally catch by value to provoke the problem
  {
    detector(ex);
  }

  return 0;
}

しかし、スライスは検出されませんでした。テストにエラーがありますか、これは VS2010 では機能しませんか、それとも最後にパターンが機能しませんか? ( ideoneの gcc 4.7.2 が気に入らなかったため、編集しました) よろしくお願いします!

4

2 に答える 2

4

あなたの論理は正しくありません。スライスは例外を MyException から std::exception に変換します。テンプレートに型を自動的に検出させるため、引数と同じ型が選択されます。同じであることが保証されています。

代わりに次のように呼び出します。

detector<MyException>(ex);
于 2013-06-20T19:05:06.007 に答える
0

これを実現する唯一の方法は、ランタイム ポリモーフィズム例外を使用することだと思います。例外クラスに仮想関数を追加し、おそらく this ポインターを返すだけで、スプライスされたオブジェクトとスプライスされていないオブジェクトを区別できるようになります。このような:

class B;
class A {
    virtual B* toB() { return NULL; }
};
class B {
    B* toB() { return this; }
};

後で、B オブジェクトになる可能性のある任意の A オブジェクトに対して実行できます。

class A* foo = bar();
class B* fooB = foo->toB();
if(fooB) {
    //whatever
}

クラスに仮想関数がない限り、C 構造体との互換性を確保するために仮想関数テーブル ポインターがオブジェクトに存在しないと主張するため、C++ はスプライシングに気付くことを実際に禁止します。 . しかし、2 つのケースを区別するには、そのポインターが必要です。

ただし、「new」で例外オブジェクトを作成しない限り、これが機能するかどうかはわかりません。例外が基本クラス型の変数にコピーされた場合、結果のオブジェクトは、作成元の派生型ではなく、間違いなくその基本クラス型になります。ただし、「throw new MyException()」は機能するはずです。

于 2013-06-20T19:20:23.323 に答える