cos と std::cos は別物だっていう話

C++には関数のオーバーロードがあるから,Cの cosf みたいに型ごとに関数を区別して書く必要が無い. cos(x) と書けば, x の型を自動で判別してくれるということだ.が,落し穴が.

using namespace std を書かずに cos(x) を呼び出すと, x の型にかかわらず cos(double) が呼び出されるようだ(g++依存かもしれないが不明).オーバーロードされた cos を呼ぶためには std::cos(x) と書かなければならない.前者でエラーが出ないから, x が long double の場合などには期待した精度が出ないことがある.気づきにくいから注意が必要だ.

サンプルコード:

#include <iostream>
#include <iomanip>
#include <cmath>
#define print(var) std::cout<<std::setiosflags(std::ios::left)\
  <<std::setw(25)<<#var"= "<<(var)<<std::endl

int main(int argc, char**argv)
{
  print(sizeof(float));
  print(sizeof(double));
  print(sizeof(long double));
  print(sizeof(cos(-0.5f)));
  print(sizeof(cos(-0.5)));
  print(sizeof(cos(-0.5l)));
  print(sizeof(std::cos(-0.5f)));
  print(sizeof(std::cos(-0.5)));
  print(sizeof(std::cos(-0.5l)));
  return 0;
}

結果:

sizeof(float)=           4
sizeof(double)=          8
sizeof(long double)=     12
sizeof(cos(-0.5f))=      8
sizeof(cos(-0.5))=       8
sizeof(cos(-0.5l))=      8
sizeof(std::cos(-0.5f))= 4
sizeof(std::cos(-0.5))=  8
sizeof(std::cos(-0.5l))= 12

何もつけない cos が, cos(double) を呼び出していることがわかる. std::cos はちゃんと引数に合わせた型を選んでくれている.