こんにちは。
初心者C++er Advent Calendar 2016の昨日の記事で面白い問題が上がっていたので、対策してみました。
記事ではuint8_t、uint16_t、uint32_t、uint64_tでオーバーロードした関数にDWORDを与えたらコンパイルエラーになってしまうとのこと。DWORDとuint32_tって同じものの筈なのでDWORDで呼び出せないって変ですね。
種明かしも記事にありました。Visual C++ではuint32_tはunsinged int、DWORDはunsigned longで定義されているので型が違うため、暗黙の型変換で曖昧になってしまうそうです。
なるほど。
関数テンプレートをSFINAEして対策できます。
すっごい宣言が長ったらしくなるのでマクロで縮めました。C++11以上で通ります。
イネーブラが無い方がスッキリするのでnullptr_tテクニックを使ってます。
# include <iostream>
# include <type_traits>
# ifdef __WIN32__
#include <windows.h>
# else
typedef unsigned long DWORD;
# endif
# define TEMPLATE(dType) \
template \
< \
typename tType, \
typename std::enable_if \
< \
(sizeof(tType) == sizeof(dType)) && \
(std::is_signed<tType>::value == std::is_signed<dType>::value), \
std::nullptr_t \
>::type=nullptr \
>
TEMPLATE(std::uint8_t) void f(tType) {std::cout << "uint8_t\n";}
TEMPLATE(std::uint16_t) void f(tType) {std::cout << "uint16_t\n";}
TEMPLATE(std::uint32_t) void f(tType) {std::cout << "uint32_t\n";}
TEMPLATE(std::uint64_t) void f(tType) {std::cout << "uint64_t\n";}
int main()
{
DWORD x = 12345;
f(x);
}