LoginSignup
2
6

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-12-24

こんにちは。

初心者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);
}
2
6
1

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
2
6