0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

0
Last updated at Posted at 2020-03-07

表題の通り。

一時しのぎの例

もっと良い方法がある人は教えて下さい:relaxed::raised_hand:

# 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 という文字列が置換されてしまう

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

# 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 さんが教えてくれました!ありがとうございます!(詳細は本記事のコメント欄を参照)

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?