C++: charとsigned charとunsigned charは違う

  • C++
( 更新)
#include <iostream>

template<typename T>
void f(T) {
	std::cout << "T" << std::endl;
}

void f(signed int) {
	std::cout << "signed int" << std::endl;
}

int main() {
	f(0); // Tとsigned intのどっちが出力される?
}

この場合は当然signed intが出力される。

#include <iostream>

template<typename T>
void f(T) {
    std::cout << "T" << std::endl;
}

void f(signed char) {
    std::cout << "signed char" << std::endl;
}

int main() {
     f('A'); // Tとsigned charのどっちが出力される?
}

でもこうするとTが出力される。罠。

解説


  • Cにおいてcharの符号は処理系定義
    • この仕様を受け継いだC++は以下の定義
      • signed char != char
      • unsigned char != char
  • 一方intは符号付きであるという定義
    • この仕様を受け継いだC++は以下の定義
      • signed int == int
      • unsigned int != int

int8_tとかuint8_tへの特殊化するとたまにやらかす。ちゃんとcharの特殊化もしようね。

ちなみにsigned charとunsiged charのオーバーロードがある時charを入れるとコンパイルが通らない(オーバーロードが曖昧っていうエラー)

void f(signed char) {}
void f(unsigned char) {}

int main() {
	f('A'); // コンパイルエラー
}

char用のオーバーロードを定義してあげるとコンパイルが通る。

void f(char) {}
void f(signed char) {}
void f(unsigned char) {}

int main() {
	f('A'); // OK
}

これに黒魔術(SFINAE)が絡んでくるといよいよ訳がわからなくなってくる...