列挙体と列挙子をリネームしたいが既存コードを書き換えたくない場合の一時しのぎ (C++)

表題の通り。

# 一時しのぎの例
もっと良い方法がある人は教えて下さい:relaxed::raised_hand:

```C++
#include <iostream>
#include <cassert>


/* 旧バージョンの列挙体と列挙子
enum class HogeEnum
{
    Taro,
    Jiro,
    Sabro
};
*/


/* 新バージョンの列挙体と列挙子。旧バージョン相当のコードを書き換えることなく、この新定義を使いたい */
enum class NewHogeEnum
{
    NewTaro,
    NewJiro,
    NewSabro
};


/* HogeEnum を NewHogeEnum 型のエイリアスとすることはできるが、列挙子の表記は旧バージョンを引き継げないためコンパイルエラー
using HogeEnum = NewHogeEnum;
*/


/* 列挙子の表記は旧バージョンを引き継げるが、HogeEnum を NewHogeEnum 型のエイリアスとすることはできないためコンパイルエラー
namespace HogeEnum {
    constexpr NewHogeEnum Taro = NewHogeEnum::NewTaro;
    constexpr NewHogeEnum Jiro = NewHogeEnum::NewJiro;
    constexpr NewHogeEnum Sabro = NewHogeEnum::NewSabro;
}
*/


/* "HogeEnum::Taro" のようなコードにおいて、 Taro は NewHogeEnum の列挙子ではないためコンパイルエラー。 
using HogeEnum = NewHogeEnum;
constexpr NewHogeEnum Taro = NewHogeEnum::NewTaro;
constexpr NewHogeEnum Jiro = NewHogeEnum::NewJiro;
constexpr NewHogeEnum Sabro = NewHogeEnum::NewSabro;
*/

/* コンパイル成功。ただし必要に応じて演算子オーバロード等の定義を追加する必要がある。そもそも型として全く別物を定義することになる
struct HogeEnum
{
    static constexpr NewHogeEnum Taro = NewHogeEnum::NewTaro;
    static constexpr NewHogeEnum Jiro = NewHogeEnum::NewJiro;
    static constexpr NewHogeEnum Sabro = NewHogeEnum::NewSabro;
    
    HogeEnum(const NewHogeEnum& NewHogeEnumVar) : value(NewHogeEnumVar) {};

    HogeEnum& operator=(const NewHogeEnum& NewHogeEnumVar)
    {
        value = NewHogeEnumVar;
        return *this;
    }
    
    operator int() const { return static_cast<int>(value); }

    bool operator ==(const NewHogeEnum& NewHogeEnumVar) { return (value == NewHogeEnumVar); }
    bool operator !=(const NewHogeEnum& NewHogeEnumVar) { return (value != NewHogeEnumVar); }
 
private:
    NewHogeEnum value = NewHogeEnum::NewTaro;
};
constexpr NewHogeEnum HogeEnum::Taro;
constexpr NewHogeEnum HogeEnum::Jiro;
constexpr NewHogeEnum HogeEnum::Sabro;
*/


/* コンパイル成功。ただしコード中のすべての Taro、Jiro、Sabro という文字列が置換されてしまう */
using HogeEnum = NewHogeEnum;
#define Taro NewTaro
#define Jiro NewJiro
#define Sabro NewSabro


int main() 
{
    static_assert(static_cast<int>(HogeEnum::Taro) == 0, "");
    static_assert(static_cast<int>(HogeEnum::Jiro) == 1, ""); 
    static_assert(static_cast<int>(HogeEnum::Sabro) == 2, ""); 

    HogeEnum hoge = HogeEnum::Taro;
    assert(hoge == HogeEnum::Taro);
    std::cout << static_cast<int>(hoge) << std::endl;

    hoge = HogeEnum::Jiro;
    assert(hoge == HogeEnum::Jiro);
    std::cout << static_cast<int>(hoge) << std::endl;

    hoge = HogeEnum::Sabro;
    assert(hoge == HogeEnum::Sabro);
    std::cout << static_cast<int>(hoge) << std::endl;

    HogeEnum fuga(hoge);
    assert(fuga == HogeEnum::Sabro);
    hoge = fuga;
    assert(hoge == HogeEnum::Sabro);
    std::cout << static_cast<int>(hoge) << std::endl;
    
    return 0;
}
```

using による列挙型の、マクロによる列挙子のエイリアスをそれぞれ定義するのが (思いついた限りでは) 一番良い方法に見えたがどうなんだろうか。

## マクロによる一時しのぎが通用しないケース

上記コードにこんなコメントを書いた

```
コード中のすべての Taro、Jiro、Sabro という文字列が置換されてしまう
```

実際、下記のように改造したコードではマクロによる一時しのぎは通用せずコンパイルエラーを引き起こす。


```C++
#include <iostream>
#include <cassert>


/* 旧バージョンの列挙体と列挙子
enum class HogeEnum
{
    Taro,
    Jiro,
    Sabro
};
*/


/* 新バージョンの列挙体と列挙子。旧バージョン相当のコードを書き換えることなく、この新定義を使いたい */
enum class NewHogeEnum
{
    NewTaro,
    NewJiro,
    NewSabro
};


/* 新規に追加した列挙体定義。これに起因するコンパイルエラーが起きる */
enum class FugaEnum
{
    Taro,
    Jiro,
    Sabro
};


/* FugaEnum の列挙子 Taro、Jiro、Sabro も置換されてしまうのでコンパイルエラー */
using HogeEnum = NewHogeEnum;
#define Taro NewTaro
#define Jiro NewJiro
#define Sabro NewSabro


int main() 
{
    static_assert(static_cast<int>(HogeEnum::Taro)  == 0, "");
    static_assert(static_cast<int>(HogeEnum::Jiro)  == 1, ""); 
    static_assert(static_cast<int>(HogeEnum::Sabro) == 2, ""); 
    static_assert(static_cast<int>(FugaEnum::Taro)  == 0, ""); // <-- ここでエラー

    ...

}
```

上記コードでもコンパイルに成功する方法を @SaitoAtsushi さんが教えてくれました！ありがとうございます！(詳細は本記事の[コメント欄](https://qiita.com/g_fukurowl/items/f1aca3b2c9bab6d20ec4#comment-246656e43630b3cce8bd)を参照)