[C++] 符号付き整数と符号なし整数の引数オーバーロード
下のようなソースコード(ここではファイル名を test.cc とします)を書きました.
#include <cstdio>
class A
{
private:
int b;
public:
A(int i) { printf("%s\n", __PRETTY_FUNCTION__); }
A(unsigned int i) { printf("%s\n", __PRETTY_FUNCTION__); }
};
int main()
{
size_t i = 10;
A a(i);
return 0;
}
これを当方が使用している Gentoo Linux 上の gcc-4.1.1 上でコンパイルします.
% g++ --version g++ (GCC) 4.1.1 (Gentoo 4.1.1) Copyright (C) 2006 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. % g++ -Wextra test.cc % ./a.out A::A(unsigned int) %
コンパイルが通り,動作します.いつもこの環境でプログラムを書いていたので,「size_t はどの環境でも unsigned int と同じ型」だと思いこんでいました.しかし,Darwin-8.8.1 (Core 2 Duo の iMac 上) 上の gcc-4.0.1 でコンパイルしたところ...
% uname -srvmpio Darwin 8.8.1 Darwin Kernel Version 8.8.1: Mon Sep 25 19:42:00 PDT 2006; root:xnu-792.13.8.obj~1/RELEASE_I386 i386 i386 iMac5,1 Darwin % g++ --version i686-apple-darwin8-g++-4.0.1 (GCC) 4.0.1 (Apple Computer, Inc. build 5363) Copyright (C) 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. % g++ -Wextra test.cc test.cc: In function 'int main()': test.cc:15: error: call of overloaded 'A(size_t&)' is ambiguous test.cc:9: note: candidates are: A::A(unsigned int) test.cc:8: note: A::A(int) test.cc:4: note: A::A(const A&) %
と,怒られてしまいました.変数 i の型を size_t から unsigned int にすると,正しくコンパイルされ,最初に述べた Gentoo Linux での結果と一致します.
そういえば size_t って組み込み型じゃなかったなぁ,なんて思い出したので,プリプロセッサの出力を見てみることにします.
g++ -E test.cc | grep size_t typedef long unsigned int size_t; using ::size_t; typedef long unsigned int __darwin_size_t; typedef long __darwin_ssize_t; typedef __int32_t __darwin_blksize_t; __darwin_size_t ss_size; __darwin_size_t uc_mcsize; __darwin_size_t uc_mcsize; (中略) size_t i = 10; %
Darwin 側には long が付いてます.ちなみに Gentoo 側では以下の通り unsigned int でした.
% g++ -E test.cc | grep size_t | head -n1 typedef unsigned int size_t; %
念のため確認しておきますと,sizeof(size_t) はどちらの環境でも 4 でした.ただ,お恥ずかしながら,size_t が unsigned int ではない 32bit 処理系も存在する,ということを今知りました.
64bit 処理系では sizeof(size_t) が sizeof(unsigned int) と等しくないので,それを利用してオーバーロードの有無を切り替えていたのですが... 今回の場合は変数のサイズでは比べられないので,何か別な基準が必要になりそうです.例えば typeid でしょうか.
% cat > test2.cc #include <cstdio> #include <typeinfo> int main() { if (typeid(size_t) != typeid(unsigned int)) puts("NOT SAME"); else puts("SAME"); if (typeid(size_t) != typeid(long unsigned int)) puts("NOT SAME"); else puts("SAME"); return 0; } % g++ test2.cc % ./a.out NOT SAME SAME %
うまくいきました.この判定プログラムの結果を使ってプリプロセッサを制御すれば,size_t が long unsigned int な環境でもコンパイルが通るようにできそうです(この辺の処理には GNU 定番の autoconf を使います).
トラックバック
トラックバック URI: https://www.pakunet.jp/hoge/trackback/2006100501
トラックバックはありません.