📝

scoped enum用オーバーロード関数

2018/09/10に公開

はじめに

今回開発時にログ用のオーバーロード関数を作成していました.しかし,scopedenum で定義した型用の関数を全種分定義するわけにもいかず,どうにかならいなかと思って調べた結果の備忘録です.

サンプルコード

main.cpp

#include <stdio.h>
#include <vector>

// retrun macro
#define RET_MACRO(retData){\
    print(__func__, retData);\
    return retData;\
}
#define RET_VOICE_MACRO(){\
    print(__func__);\
    return;\
}

enum class Hoge
{
	A = 0,
	B,
	C,
};

// scoped enum
template<typename T>
void print(const char* funcName
, T num
, typename std::enable_if<std::is_enum<T>::value, std::nullptr_t>::type = nullptr)
{
	printf("%-20s : %d\n", funcName, num);
}
// double
void print(const char* funcName, double num)
{
	printf("%-20s : %f\n", funcName, num);
}
// int
void print(const char* funcName, int num)
{
	printf("%-20s : %d\n", funcName, num);
}
// vector
template<typename T>
struct is_vector : std::false_type {};
template<typename T>
struct is_vector<std::vector<T>> : std::true_type {};
template<typename T>
void print(const char* funcName
, T num
, typename std::enable_if<is_vector<T>::value, std::nullptr_t>::type = nullptr)
{
	printf("%-20s : vec\n", funcName);
}
// other
void print(const char* funcName, ...)
{
	printf("%-20s : --\n", funcName);
}


// return int
int retIntFuc()
{
	RET_MACRO(5);
}
// return double
double retDoubleFuc()
{
	RET_MACRO(0.5);
}

// return scoped enum
Hoge retScopedEnumFuc()
{
	RET_MACRO(Hoge::B);
}

// return vector
std::vector<int> retVectorFunc()
{
	std::vector<int> vec;
	RET_MACRO(vec);
}

// retrun other
struct Othr
{
	int a;
	int b;
};
Othr retOtherFunc()
{
	Othr other = {};
	RET_MACRO(other);
}

// retrun other
void retVoidFunc()
{
	RET_VOICE_MACRO();
}

int main()
{
	retIntFuc();
	retDoubleFuc();
	retScopedEnumFuc();
	retVectorFunc();
	retOtherFunc();
	retVoidFunc();

	return 0;
}
// return double
double retDoubleFuc()
{
    RET_MACRO(0.5);
}

// return scoped enum
Hoge retScopedEnumFuc()
{
    RET_MACRO(Hoge::B);
}

// return vector
std::vector<int> retVectorFunc()
{
    std::vector<int> vec;
    RET_MACRO(vec);
}

// retrun other
struct Othr
{
    int a;
    int b;
};
Othr retOtherFunc()
{
    Othr other = {};
    RET_MACRO(other);
}

// retrun other
void retVoidFunc()
{
    RET_VOICE_MACRO();
}

int main()
{
    retIntFuc();
    retDoubleFuc();
    retScopedEnumFuc();
    retVectorFunc();
    retOtherFunc();
    retVoidFunc();

    return 0;
}

実行結果

retIntFuc            : 5
retDoubleFuc         : 0.500000
retScopedEnumFuc     : 1
retVectorFunc        : vec
retOtherFunc         : --
retVoidFunc          : --

解説

23 ~ 51 行目までの print 関数がログ用の関数で,今回の肝となるのが 22 ~ 26 行目の scopedenum 用の print 関数です.
大まかな流れは以下通りです.
・渡された引数の型が enum か否かを「std::is_enum」にて判定を行います.enum であれば true を返す.
・「std::enable_if」は「is_enum」が true となれば enbale_if は「std::nullptr_t」型として実態化.
・これにより enum 以外の場合 SFINAE によって,オーバーロード解決の候補から外され,enum のときに実行される関数ができる.

私自身少しふわっとした理解なので,間違い等あれば指摘していただけるとありがたいです.
また,vector は後で必要になったので,参考文献 4 を参考にメタ関数等作成しました.

参考文献

1.enable_if - cpprefjp - C++日本語リファレンス
2.enable_if クラス
3.【C++ Advent Calendar 2016 22 日目】C++ で enable_if を使うコードのベストプラクティス
4.C++メタ関数のまとめ

Discussion