ゲーム作りは楽しい

なんか書く

CocosCreator Effect classを考える

挨拶

久しぶりの投稿です。 4月から就職しました。(一応ゲームエンジニア)
最近はCocosCreatorを触っているのでそれ関連でEffectの管理を考えてみました。

Effect.js

cc.ComponentとしてEffectのマネージャーを作成する

export let Effect = cc.Class({
    extends: cc.Component,

    properties: {
        _effects: [],
        _isPause: false
    },
    statics: {
        main: null
    },

    // LIFE-CYCLE CALLBACKS:

    onEnable() {
        if (Effect.main)
            return;
        Effect.main = this;
    },
    onDisable() {

        if (Effect.main !== this)
            return;

        Effect.main = null;

    },
    update(dt) {
        if (this._isPause)
            return;
        //パフォーマンス不安
        this._effects = this._effects.filter((elm) => {
            if (elm._effect === null) {
                return false;
            }
            elm._timer += dt;
            let isDestory = !elm._effect.update(elm._timer);
            if (isDestory) {
                elm._effect.onDestroy();
            }
            return !isDestory;
        });
    },
    add(effect) {
        if (effect instanceof IEffect)
            this._effects.push({ _timer: 0, _effect: effect });
        else
            throw "effect type is must extends `IEffect`";
    },

    clear() {
        this._effects = [];
    },
    pause() {
        this._isPause = true;
    },
    resume() {
        this._isPause = false;
    }
});

add関数に渡すのはIEffectを継承して実装したエフェクトのインスタンスとする

export class IEffect {
    constructor(node = null) {
        this.node = node;
    }
    update(timeSec) {
        return timeSec <= 1.0;
    }
    onDestroy() {
        if (this.node !== null)
            this.node.destroy();
    }
}

Effectのupdate(dt)が追加したエフェクト全てのupdate(timeSec)に各経過時間を渡して呼んでいる
コンストラクタでnodeを登録しておけば自動でdestroy()をよんでもらえる。
cc.Nodeやcc.Componentを渡すことができる

Sample1

Sample1.js

import { Effect, IEffect } from "Effect";

class Sample1 extends IEffect {
    update(timeSec) {
        this.node.scale += 0.01;
        return timeSec <= 1;
    }
}
cc.Class({
    extends: cc.Component,

    start() {
        this.t = 0;
        Effect.main.add(new Sample1 (this.node));
    },
    update(dt) {
    },
});

Effectコンポーネントがアタッチされたノードをもつシーンで このスクリプトがアタッチされたプレハブを生成したりすればよい

C++ 範囲ベースforに自分で作ったclassを対応させる

はじめに

NITMic Advent Calender 25日目 担当のマホウです。

メリークリスマス!

僕はサンタさんに免許更新のお金をもらいました! ラッキーなことに初回の更新なのに講習を地元でうけれることになりました。

今日は C++の範囲ベースfor

//こーゆーの
for(auto&& elm:v)
{}

に自分の作ったクラスを対応させる方法を紹介します。

範囲ベースfor とは

そもそも範囲ベースfor(range-based for)とは 配列とかコンテナとかの要素を全て回したりするときに、とても使える構文で C#だとforeachってキーワードがあったりするあれみたいなものです。

例えば、こんなコード

int main()
{
    int ar[] = { 1,2,3 };
    for (size_t i = 0; i < std::size(ar); ++i)
    {
        std::cout << ar[i] << std::endl;
    }

    return 0;
}

int main()
{
    int ar[] = { 1,2,3 };
    for (int elm : ar)
    {
        std::cout << elm << std::endl;
    }

    return 0;
}

のようにかけます。

int elmの部分はコピーが発生するので、値を書き換えたいときやコピーのコストがかかるものは(というかclassは全部といってもいい) auto& elmのような参照にしておく必要があります。
書き換えないときはconst auto&にするとよいでしょう
ユニヴァーサル参照auto&&とかもあり(詳しいことは自分で調べて)

予断ですが普通forの時にint iとsize等の比較は符号有り無し比較で警告が出るのでsize_t等unsignedにする癖をつけといたほうがいいかもね

Range Concept

さっそくですが ある要件さえ満たしていれば範囲ベースforで使うことができます。

その要件は

  • begin()とend()メソッドを持っている(正確にはstd::begin/endをオーバーロードしてもいいのだがとてもオススメはしない)
  • begin()とend()の返り値の型は
    • operator *
    • operator ++(前置)
    • operator != を持つ

これだけです。 C++17ではない場合begin()とend()の返り値の型は同じでなければなりません。

ここなんか読むと範囲forがどう展開されるか書いてあるので、わかりやすいです。 cpprefjp.github.io

class Hoge 
{
    int m_ar[3];

public:
    Hoge():
        m_ar{1,2,3}
    {}
    /*
   ポインタ型は++ * !=をもつ
   */
    int* begin()
    {
        return &m_ar[0];
    }
    int* end()
    {
        return &m_ar[3];
    }

};
int main()
{

    Hoge hoge;

    for (int elm : hoge)
    {
        std::cout << elm << std::endl;
    }

    return 0;
}

応用例 逆順範囲for

ほしいと思ったことありませんか? 要件をしった僕達ならもう実現できちゃいます。

#include<iterator>

namespace range
{
    template<class Range>
    using range_value_t = typename std::iterator_traits<decltype(std::begin(std::declval<Range&>()))>::value_type;

    template<class Range>
    using range_iterator_t = decltype(std::begin(std::declval<Range&>()));

    template<class Range>
    using range_const_iterator_t = decltype(std::cbegin(std::declval<Range&>()));

    namespace detail
    {
        template<class Range>
        class ReverseRange
        {
            using iterator = std::reverse_iterator<range_iterator_t<Range>>;
            using const_iterator = std::reverse_iterator<range_const_iterator_t<Range>>;

        private:
            Range m_range;
        public:
            ReverseRange(Range&& range) :
                m_range(std::forward<Range>(range))
            {}

            iterator begin()
            {
                return iterator{ std::end(m_range) };
            }
            iterator end()
            {
                return iterator{ std::begin(m_range) };
            }

            const_iterator begin()const
            {
                return const_iterator{ std::end(m_range) };
            }
            const_iterator end()const
            {
                return const_iterator{ std::begin(m_range) };
            }
            std::size_t size()const
            {
                return std::size(m_range);
            }
        };
    }


    //逆順
    constexpr struct Reverse_OP
    {
        template<class Range>
        detail::ReverseRange<Range> operator ()(Range&& v)const
        {
            return detail::ReverseRange<Range>(std::forward<Range>(v));
        }

        template<class Range>
        friend auto operator -(Range&& v, Reverse_OP op)
        {
            return op(std::forward<Range>(v));
        }

    }reverse;
}
int main()
{

    int ar[] = { 1,2,3 };

    for (int elm : ar - range::reverse)
    {
        std::cout << elm << std::endl;
    }

    return 0;
}

最後に

25日間みなさんお疲れ様でした。 いろんな記事がよめて、特に自分があまり触れていない分野なんかは本当に勉強になりました。 今年はためしにやってみた感じですが、手ごたえはどうだったでしょうか?

いいね!って感じたならまた来年以降もやっていってくれたら良いかなと思います。

個人的によく使うノンダイアトニックコード紹介+α

はじめに

NITMic Advent Calendar 2017 21日目担当のマホウです お前も何回目だって言われそうですが、空いていたら埋めます。

今日はせっかくなので作曲の話をします。

  • プログラマーの職だった僕が作曲をはじめたきっかけの話
  • 個人的によく使うノンダイアトニックコードの紹介

をします!

コード(プログラミングのコードではない)

プログラミングの話を期待してた人は 昨日別のカレンダーで紹介した記事があるのでこっちで許して

qiita.com

作曲を始めたきっかけ

今年で作曲を始めてから3年目くらいになりますが、なんで部でプログラマーをやっていた僕が作曲を始めたかというと、答えはシンプルに面白そうだったからです。

にとみくを見学するまでパソコンで曲を作れるということも知りませんでした。DTM?何それ状態
ただ、曲を聴いたり歌ったり、どこからともなくメロディを思いついたりと音楽はもともと好きだったのと、
BGMが自分で作れたらゲーム制作で役立ちそうって思って興味を持ちました。
もともとモノづくり自体好きですしね!!!

かつて、にとみくの新入生歓迎会の日に
「志望役職はオールです」「提督なのです!」っていった日が懐かしく思えます。

で、ある日なんとなく「蟻さんに作曲教えてもらお!」って言ったら蟻さんが僕のPCに「Domino」を入れて環境も整えてくれたので僕は作曲を始めることができました。
すごく、適当な始まり方でしょ? でもそんなもんですよ、きっかけなんて。

ありがとう蟻さん

その後も、ことぶき君に「 FL Studio 」というちゃんとした作曲ソフトの使い方を教えてもらったり 先輩方から音楽理論を教えてもらったりと、、
なんやかんやあって今では作曲サークルにも所属してます♪

ちなみに楽器経験は皆無で小学生の時もリコーダーのドとレが鳴らせないレベルだし
最初は鍵盤でドとシ、ミとファの間には黒鍵がないことも知りませんでした。
和音#とは ってかんじでした。
ベースって何か知らなかった、ドラムも何もわからなかった。

そんな僕でも、調べたり、色々教えてもらいながら数をこなしていくうちに、少しずつ自分の曲が作れるようになっていきました!
本当にいい趣味を見つけたと思うし、にとみくに入ってなかったら作曲を始めることもなかったかもしれないと思うと奇跡にも思えます。

長々と話をしてきましたが、ごめん、僕が一番言いたいことはこれから言うこと

せっかく
プログラミングができる人、絵が描ける/モデリングができる人、曲が作れる人
いろんなことができる人が身近にいるのだから、興味をもって他の世界をのぞいてみるのも面白いかもしれないよ?
新しい出会いがあるかもしれません!

ただ創作は嫌々やるものでもないので、無理にやれとも言いませんし、最終的には楽しんでいただければ幸いです。
モチベがない時は無理にやんなくてもいいんです。

以下は普通に作曲の話。 音楽初心者なので説明は間違ってるかもしれません。

ノンダイアトニックコードとは

コード(chord)とは和音のことで、 ドミソとかシファソのようなに同時に鳴らす音のことを言うんだと思います。 三つだったら三和音、ドミソシのように四つだったら四和音とか言ったりします。

で、ダイアトニックコードとはkey=Cのときは「ドレミファソラシ」だけで構成されるコードのことをいい 皆がよく知っている

C Dm Em F G Am Bm-5
ドミソ レファラ ミソシ ファラド ソシレ ラドミ シレファ

も含まれます。

じゃあ、ノンダイアトニックコードとは何かというと、
ダイアトニックコードじゃないコードになります。

「ドレミファソラシ」で曲を作っていたのに、それ以外の音も使ったコードってことです。 そういったコードが上手く使えるようになっていくと、「あ!ここ、エモい!」ってなる曲も作れるようになるかもしれません。

その場合メロディやベースなんかもそのスケール外の音を通してあげることでより強調できるかもしれません。(そうしないとやばい時もあります…)

今日は僕がよく使うノンダイアトニックコード(を含む進行)を紹介したいと思います。

すべてkey=C,Amで紹介します。  

C7


C7はF(IV)のセカンダリードミナント

 Gm7 C7 | F

ツーファイブワンのセットで使うことが多い

Cdim

こないだ知ったばかりなので、まだ最新曲でつかってみた程度ですが紹介しておきます。
トニック・ディミニッシュというそうです。

 C | Cdim

D7


ドッペルドミナントとか言うやつ G(V)のセカンダリードミナント

 Dm | D7 | G

E7

僕がめっちゃ好きな奴


王道進行のIIImをIII(7)にした版 Am(VIm)のセカンダリードミナント

 F | G | E7 | Am

さらにツーファイブにするのもあり

 F | G Bm7-5 | E7 | Am

短調の曲のドミナントVm7はV7にするのもよし

 Am | G | F | E7

Fm


とりあえずエモいから使っていけ

 F | Fm 

F#dim


トニックの代わりに使える奴らしい、D7のルート音をなくしたやつとも見れるのか?

 F#dim | G

Gm7


前使ったことあるやつだと

 C | Gm7 | FM7 | FmM7 | Em 

あとは先ほど同様C7と一緒に使うのがよくやる

A7


王道進行のVImをVI(7)に

 F | G | Em | A

Dmにつなげるときに使ったり。 EmEm7-5とかにしてみても面白いかも?

短調の曲でも最後Imで終わらずIで終わるのもあり
ピカルディ終止っていうそうです

 F | Em7 | A

B♭7

Eの裏コードになる和音

 F | G | B♭7 | Am 

ナインスにするのはとてもあり!(スケール内の音を通る)

 Em | Am | B♭9 | G7

その他

クリシェを使ったりするとノンダイアトニックコードがでてきたりする


僕の大好きな下降クリシェ。エモいです。 Bメロとか曲の最後のほうで使いたくなる

 Am | Caug | C | F#m7-5

さらにFM7につなげるのもあり

たまにAメロ前とかにいれたくなる上がっていくやつ

 C | Fm | F#dim | C7

他にも昔使ったことあるやつ

 Am | F | F#dim | C5

さいごに

今日紹介したのはあくまで僕がよく使うやつ(and使ったことある程度のやつ)を紹介した程度です。
むしろ使ったことないやつは紹介してない(今度はC#を使ってみよう)
他にもいいのがたくさんあると思いますし、自分のお気に入りを見つけていきましょう!

自分の好きな曲からパクっていけ!!

PS.遅れてすいませんでした。

C++:非virtualデストラクタ継承の話

デストラクタがvirtualでないclassの継承には注意が必要という話を聞いたことがある人もいると思いますがその話をちょっとします

struct A
{
    A() = default;

    ~A() 
    {
            std::cout << "A destructor" << std::endl;
    }
};

struct B:A
{
    B() = default;

    ~B()
    {
        std::cout << "B destructor" << std::endl;
    }
};

int main()
{
    {
        std::unique_ptr<B> a = std::make_unique<B>();
    }
    {
        std::unique_ptr<A> a = std::make_unique<B>();
    }
    return 0;
}

いまAのデストラクタはvirtualではありません。
このときの出力は

B destructor
A destructor
A destructor

になります。

非virtualデストラクタを持つ型からアップキャストした場合、破棄されるときに呼ばれるのは 基底classのデストラクタのみ になるので注意。
じゃあ基底classのデストラクタをvitualにすればいいじゃん? 確かにそうですがたとえば
std::vectorなどのような標準ライブラリのclassなどで変更がきかない場合もあります。
でも、vectorを拡張したいとか思ったことありませんか?

アップキャストせずに使えばもちろん問題はないですがそれでも間違えてやってしまう場合もないとはいえません。
(派生先のデストラクタが何もしてないなら最悪呼ばれなくてもいいっちゃいいのかな?)
そういう時、より安全に使うためにはprotected継承してあげるのがよくある例だったりします。

struct A
{
    A() = default;

    ~A() 
    {
            std::cout << "A destructor" << std::endl;
    }
};

struct B:protected A
{
    B() = default;

    ~B()
    {
        std::cout << "B destructor" << std::endl;
    }
};

int main()
{
    {
        std::unique_ptr<B> a = std::make_unique<B>();
    }
    {
        //std::unique_ptr<A> a = std::make_unique<B>(); これがコンパイルエラーになる
    }
    return 0;
}

こうすることで、そもそもアップキャストして使うことそのものをエラーにできます。 ちなみに、Siv3Dのs3d::Arraystd::vectorをprotected継承してます。

最後に、protected継承したということは、基底classでpublicだったものがすべてprotectedになるので 必要なものはusingしてあげるといいでしょう。

struct A
{
    A() = default;

    ~A()
    {
        std::cout << "A destructor" << std::endl;
    }
    void hoge() {}
};

struct B :protected A
{
    B() = default;

    ~B()
    {
        std::cout << "B destructor" << std::endl;
    }

    using A::hoge;

};

ハッカソンの感想

NITMic Advent Calendar4日目

昨日、第10回名工大ハッカソンinワンダープラネットが行われたのでその感想

名工大ハッカソンとは?

8時間という時間のなかで即席チームでテーマに沿ったゲームを作る
というイベントです

自分は前回まで運営を行っていたので久しぶりに参加側にまわりました
今回は初参加の人も多く来てくれて、イベントとして確実に盛り上がってきているのを感じました。

いつもはその名の通り名工大の教室を借りて行うのですが今回はクラッシュフィーバーなどで有名なワンダープラネットさんの会場を借りて開催されました。
社員の方に審査やメンターをしていただきました!

今回のテーマは「ワンアクション+ふる」でした

「ふる」の解釈の仕方はいろいろあって
雨が降る、シェイクする、いっぱい、古い、告白をふる、奈良県布留市など...

特に多かったのは
異性をふると捉えたチームでした
男や女を振り投げたりビンタしたりと言った感じでした

そんな中自分たちのチームは思いつく「ふる」をたくさん盛り込んだゲームを作りました。

f:id:mahou_ptr:20171204120157j:plain
f:id:mahou_ptr:20171204120219j:plain

上から色々なものが降ってきて
「ふる」ものは、ふるに
「ふるじゃない」ものは、ふらないに
振り分けていきます

例えば
☔は「ふる」なので、ふるに
☀は「ふるじゃない」なので、ふらないに
バットは「ふる」なので、ふるに
バスケットボールは「ふるじゃない」なので、ふらないに
と言った感じです

スマホでの操作も意識して作っていましたが時間が間に合わずPCでの成果発表となりました

結果はなんと優勝!

ハッカソンで優勝はたぶん初めてだったので普通に嬉しかったです

さいごに
今回で10回目となる名工大ハッカソンですが、毎回最後に言っているとおり本当に回を重ねる度に作品のクオリティが上がっているのを感じます
今回どこのチームも遊べる段階までいけていましたし細かいとこも手が回っていたように感じました。

今後も第11回へと続いていくと思うので今回参加されなかった人も興味があれば是非参加してみてください!
ほかの学校の方との交流にもなって刺激ももらえます!

PS. 帰りにミスタードーナツでタダ飯を貰い忘れたのがその日一番のショックでした

ブログを作って記事を書こう!

NITMic Advent Calenderが今日からスタート! 

1日目はマホウさんです。

今回、プログラマーだけでなく絵師さんや音屋さんたちも参加できたほうが良いと思って Adventer というサービスを使ってみたのですが、直接記事を書く機能が存在してなくて、リンクを与える形式になっているので、すでに自分の記事を書ける環境を持ってない人の場合少し手間がかかってしまいます。(最悪DropboxとかのURLでもいいんだぜ)

そこで、この際いっそ ブログを初めてみてはどうでしょうか? という話をします

この記事もまさに、はてなブログで書かれています。 他にも、AmebaとかFC2とか、名前くらいは聞いたことあるんじゃないかな?と思います
ちなみにYahooブログはオススメしません…

学んだことを記事として自分なりにまとめることで理解を深めたり、たんに趣味の話をしたり、日記を書いたり、使い方はいろいろあります。

でも、ブログを始めたからといって無理に書く必要はありません!
僕も全然ブログが続かない人です><
ふと思い立った時に情報を発信する手段として ブログは持っている分に損はない のです!

この記事を見てくれた君もブログを作って、是非カレンダーを埋めていってほしいぞい

もっと気軽に記事が書けるサービス知ってたら教えてください!

ちなみにプログラマーの場合

ブログを持たなくても

  • Qiita
  • Gist

等で気軽に記事をかけます

さいごに

今回NITMicでもやってみることになった「アドベントカレンダー」ですが、個人的な年末の楽しみになっていたりもします。
某専門学校もQiitaでOB,OGも含めたアドベントカレンダーをやっているので、いいなぁと思い老害でありながら勝手に作っちゃいました!
時期的には工大祭後早々でもあり、中間試験も忙しい時期でしょうが皆で技術の共有とかができるいい機会なので来年以降も続いていったらいいなぁと思ってたりします!

PS. 星のカービィバトルデラックス買って徹夜でやってたのと、カラフルトーンのアプデ準備でまる2日寝てない状態なのでくそねむいですzz
もう冬だけど秋アプデしました、よければどうぞ⇒ ColorfulTone

自作列挙型 enum to string メモ書き

自作列挙型を作っていますが

enumから文字列への変換をめちゃスマートに扱えるように実装できたと思ったがMSVCでしかコンパイルできないコンパイラ依存になってしまった

メモ程度にコードをあげておきます

 

#pragma once
#include<string>
#include<unordered_map>

#define EXPAND( x ) x
#define IE_FOR_EACH_1(_macro,e1)_macro(e1)
#define IE_FOR_EACH_2(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_1(_macro,__VA_ARGS__) )
#define IE_FOR_EACH_3(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_2(_macro,__VA_ARGS__) )
#define IE_FOR_EACH_4(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_3(_macro,__VA_ARGS__) )
#define IE_FOR_EACH_5(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_4(_macro,__VA_ARGS__) )
#define IE_FOR_EACH_6(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_5(_macro,__VA_ARGS__) )
#define IE_FOR_EACH_7(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_6(_macro,__VA_ARGS__) )
#define IE_FOR_EACH_8(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_7(_macro,__VA_ARGS__) )
#define IE_FOR_EACH_9(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_8(_macro,__VA_ARGS__) )
#define IE_FOR_EACH_10(_macro,e1,...)_macro(e1) EXPAND( IE_FOR_EACH_9(_macro,__VA_ARGS__) )

//必要次第追加
#define IE_GET_FOR_EACH(e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,NAME, ...) NAME
#define IE_FOR_EACH(macro,...) EXPAND(IE_GET_FOR_EACH(__VA_ARGS__,IE_FOR_EACH_10,IE_FOR_EACH_9,IE_FOR_EACH_8,IE_FOR_EACH_7,IE_FOR_EACH_6,IE_FOR_EACH_5,IE_FOR_EACH_4,IE_FOR_EACH_3,IE_FOR_EACH_2,IE_FOR_EACH_1)(macro, __VA_ARGS__))

#define IE_MAPPING_ENUM_VAL(name) \
[]()\
{\
   struct Check\
   {\
       int v=0;\
       template<class... Args>\
       Check(const Args& ...args)\
       {\
           constexpr int size = sizeof...(args);\
           if constexpr(size == 1)\
           {\
               v = name;\
           }\
           if constexpr(size == 2)\
           {\
               int name;\
               v = name;\
           }\
       }\
   };\
   if constexpr(ie::detail::NameCheck(#name))\
   {\
       return Check(1).v;\
   }\
   else\
   {\
       return Check(1, 2).v;\
   }\
\
   return 0;\
}()

#define IE_MAPPING_TO_STRING(name) {IE_MAPPING_ENUM_VAL(name), ie::detail::MappingEnumString( #name )},

namespace ie
{
    namespace detail
    {
        struct Value
        {
            constexpr Value() = default;
            constexpr Value(const int& other) :
                value(other)
            {}
        protected:
            int value = 0;
        };

        constexpr bool NameCheck(const char* test)
        {
            for (int i = 0; test[i] != '\0'; ++i)
            {
                if (test[i] == '=')
                {
                    return false;
                }
            }
            return true;
        }
        std::string MappingEnumString(const std::string& str)
        {
            return str.substr(0, str.find('='));
        }
    }
}


#define INTEGER_ENUM(...)\
struct : ie::detail::Value{\
   using  _ENUM=enum { __VA_ARGS__ };\
   using Value::Value;\
   decltype(auto) operator +=(int value) { *this = this->value + value;    return *this; }\
   decltype(auto) operator -=(int value) { *this = this->value - value;    return *this; }\
   decltype(auto) operator *=(int value) { *this = this->value * value;    return *this; }\
   decltype(auto) operator /=(int value) { *this = this->value / value;    return *this; }\
   decltype(auto) operator %=(int value) { *this = this->value % value;    return *this; }\
   decltype(auto) operator ++() { *this = this->value + 1; return *this; }\
   decltype(auto) operator --() { *this = this->value - 1; return *this; }\
   decltype(auto) operator ++(int) { auto ret = *this; *this = this->value + 1; return ret; }\
   decltype(auto) operator --(int) { auto ret = *this; *this = this->value - 1; return ret; }\
   constexpr operator _ENUM()const{ return static_cast<_ENUM>(value); }\
   std::string to_string()const\
   {\
       static std::unordered_map<int, std::string> map\
       {\
           IE_FOR_EACH(IE_MAPPING_TO_STRING, __VA_ARGS__ )\
       };\
       if (map.find(value) == map.end())\
       {\
           return "Unknown:" + std::to_string(value);\
       }\
       return map.at(value);\
   }\
}

使い方は

using Example = INTEGER_ENUM(
    A,
    B,
    Default = A
);

int main()
{
    Example a = Example::Default;

    std::cout<<a.to_string();
//出力 A
    return 0;
}

とやるだけで非常にシンプルです。 INTEGER_ENUMマクロが無名構造体を生成してto_string()メソッドも自動生成してくれるというものですが MSVCのラムダ内ならメンバtemplateが使えることや、templateの文法エラーのチェックタイミングなどの関係でほかのコンパイラでは使用できません