自分用覚え書き:テンプレートと文字列リテラルの罠のようなもの

C++ Templates: The Complete Guideの57ページにこんなコードがあった。

//---------------------------------------------------------------------------

#pragma hdrstop

#include <tchar.h>
#include <string>

//---------------------------------------------------------------------------

#pragma argsused

// note: reference parameters
template <typename T>
inline T const& max (T const& a, T const& b)
{
  return  a < b  ?  b : a;
}

int _tmain(int argc, _TCHAR* argv[])
{
  std::string s;

  ::max("apple","peach");   // OK: same type
  ::max("apple","tomato");  // ERROR: different types
  ::max("apple",s);         // ERROR: different types

  return 0;
}

ぶっちゃけた話、2番目のmaxが何故エラーになるかよく判らなかったおいら。エラーメッセージ*1からすると、両方とも"const char *"じゃないかと。

C++は実行時型情報を取得できるので、こんなコードで「正体」を探ってみる。

//---------------------------------------------------------------------------

#pragma hdrstop

#include <tchar.h>
#include <typeinfo>
#include <iostream>

//---------------------------------------------------------------------------

#pragma argsused

int _tmain(int argc, _TCHAR* argv[])
{
  std::cout << "typename \"apple\" is " << typeid("apple").name() << std::endl;
  std::cout << "typename \"peach\" is " << typeid("peach").name() << std::endl;
  std::cout << "typename \"tomato\" is " << typeid("tomato").name() << std::endl;

  return 0;
}

typeid演算子は実行時型情報であるtype_infoクラスを返す演算子。type_infoクラスのnameメソッドでその型名を取得する。

コマンドラインコンパイル&実行。

D:\home\A7M\BCBTEST\template_test1>bcc32 File1.cpp
CodeGear C++ 6.10 for Win32 Copyright (c) 1993-2008 CodeGear
File1.cpp:
Turbo Incremental Link 5.95 Copyright (c) 1997-2008 CodeGear

D:\home\A7M\BCBTEST\template_test1>File1
typename "apple" is char[6]
typename "peach" is char[6]
typename "tomato" is char[7]

つまり、最初のmaxの呼び出しは、char[6]のconst参照とchar[6]のconst参照を渡しているので、同一型と見なされ、2番目のmaxはchar[6]のconst参照とchar[7]のconst参照を渡していたから、違う型と見なされ、エラーになると。エラーメッセージだけを見るとハマる例かも。(おいらだけかもしれないけど・・・。

他にハマる例として、STL

std::make_pair("key", "value")

が挙げられていたので、罠と言えば罠かも。

*1:[BCC32 エラー] File1.cpp(24): E2285 'max(const char *,const char *)' に一致するものが見つからない