メニュー
ブログ更新履歴
コンテンツ更新履歴
リンク
  • rlib-MML WebApp
  • MML (Music Macro Language) をコンパイルし、再生やファイル出力(MP4、標準MIDIファイル)をブラウザ上で行えます。
  • Magome
  • クラウドベースのMIDIシーケンサ
    音楽制作に興味のある方を対象に、スタンドアロンでも使え、ネットならではの面白さも兼ね備えた音楽制作アプリの提供を目指しています。
twitter
  
Cur: 2021-08-08 (Sun) 22:45:20 takatsuka source
Line 1: Line 1:
 +変数の型によって処理を切り替えたいことが稀によくあるんじゃないかと思います。
 +C++ では RTTI なる情報で実行時に型を判断出来るので以下のようなコードが書けます。
 +
 +#prettify{{
 +struct Animal {
 +    virtual ~Animal() {} // ポリモーフィックにする
 +};
 +struct Dog : public Animal {};
 +struct Cat : public Animal {};
 +
 +void func(Animal* p) {
 +    if (typeid(*p) == typeid(Dog)) { // 型が Dog なら
 +     // ・・・
 +    } else if (typeid(*p) == typeid(Cat)) { // 型が Cat なら
 +     // ・・・
 +    }
 +}
 +}}
 +&font(70%){コンパイル時に型が判明する場合は if constexpr などもアリですが、本稿は実行時に判断する場合の話です。};
 +
 +
 +これで十分事足りるのですが、もう少し粋に書きたい場合もあると思います。
 +if 文の羅列ではなく switch~case みたいな感じで。
 +がしかし switch~case で分岐できる式は整定数式のみです。
 +そこで、switch~case とまではいきませんがそれっぽい条件分岐として std::type_index をキーにした std::map を使った書き方です。
 +
 +&font(70%){std::type_index は C++11 から使えますが、以下コードは C++17 での書式も使っています。};
 +#prettify{{
 +int main(void){
 +    using namespace std;
 +
 +    // クラス定義
 +    struct Car {
 +     virtual ~Car() {}
 +    };
 +    struct Nissan : public Car {};
 +    struct Silvia : public Nissan {};
 +    struct Skyline : public Nissan {};
 +    struct Toyota : public Car {};
 +    struct Chaser : public Toyota {};
 +
 +    const std::vector<std::shared_ptr<Car>> v = { // サンプル
 +     make_shared<Nissan>(),
 +     make_shared<Silvia>(),
 +     make_shared<Skyline>(),
 +     make_shared<Toyota>(),
 +     make_shared<Chaser>(),
 +     make_shared<Car>(),
 +    };
 +
 +    // それぞれの型に対応したコードを std::map で構築
 +    // 注: static 変数であることが実行速度では有利です(この例では1度しか通らないのでアレですが・・)
 +    static const std::map<std::type_index, std::function<void(void)>> map = {
 +     {typeid(Nissan), [] {
 +     cout << "NISSAN" << endl;
 +     }},
 +     {typeid(Silvia), [] {
 +     cout << "NISSAN SILVIA" << endl;
 +     }},
 +     {typeid(Skyline), [] {
 +     cout << "NISSAN SKYLINE" << endl;
 +     }},
 +     {typeid(Toyota), [] {
 +     cout << "TOYOTA" << endl;
 +     }},
 +     {typeid(Chaser), [] {
 +     cout << "TOYOTA CHASER" << endl;
 +     }},
 +    };
 +
 +    for (const auto i : v) {
 +     if (auto j = map.find(typeid(*i)); j != map.end()) { // mapから検索
 +     j->second(); // 実行
 +     } else {
 +     cout << "unknown" << endl; // 定義ナシ
 +     }
 +    }
 +}
 +}}
 + 実行結果
 + NISSAN
 + NISSAN SILVIA
 + NISSAN SKYLINE
 + TOYOTA
 + TOYOTA CHASER
 + unknown
 +
 +
 +
 +この程度のボリュームの例でも、if 文の羅列よりは見通しもよいかなーと思います。
 +
 +
 +ちなみに C++03 くらいのコンパイラでも RTTI がサポートされていれば同じこと(型がキーの std::map)が出来るので目新しい小技ではありません。がしかしココまでシンプルには書けません。
 +C++は難しげな機能も沢山追加されていますが地味な改修もとても有難いです。
 +C++関係者の皆様には感謝です。
  

  • Backup diff of 技術系備忘録/C++/小技/型で条件分岐(No. All)

Front page   Diff Backup Copy Rename ReloadPrint View   New Page Page list Search Recent changes   Help   RSS of recent changes (RSS 1.0) RSS of recent changes (RSS 2.0) RSS of recent changes (RSS Atom) Powered by xpWiki
Counter: 2755, today: 5, yesterday: 0