整数型の大きさで関数をオーバーロードする方法

More than 1 year has passed since last update.

こんにちは。

初心者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);
}
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.