野良C++erの雑記帳 このページをアンテナに追加 RSSフィード Twitter

2011-08-25 せんせー! 未実装はバグに入りますか?

C++0x の SFINAE で気づいたこと

関連: http://d.hatena.ne.jp/gintenlabo/20110413/1302675301


C++0x関数テンプレートデフォルトテンプレート引数を取れるようになったことで可能になった,

extern void* enabler;

template < typename T,
  typename std::enable_if<
    std::is_arithmetic<T>::value
  >::type*& = enabler
>
void f( T ) {
  std::cout << "T is arithmetic" << std::endl;
}

template < typename T,
  typename std::enable_if<
    std::is_pointer<T>::value
  >::type*& = enabler
>
void f( T ) {
  std::cout << "T is pointer" << std::endl;
}

っていうコードって,イチイチ enabler を定義しなくても,

template < typename T,
  typename std::enable_if<
    std::is_arithmetic<T>::value
  >::type* = 0
>
void f( T ) {
  std::cout << "T is arithmetic" << std::endl;
}

template < typename T,
  typename std::enable_if<
    std::is_pointer<T>::value
  >::type* = 0
>
void f( T ) {
  std::cout << "T is pointer" << std::endl;
}

でよくね? って思ったので,ちょっと試してみた.


が,うまくいかない. http://ideone.com/c9atG


結論から言うと,規格の 14.3.2/5 によれば,このコードは ill-formed で意図したようには動作せず,正しくは

template < typename T,
  typename std::enable_if<
    std::is_arithmetic<T>::value
  >::type* = nullptr
>
void f( T ) {
  std::cout << "T is arithmetic" << std::endl;
}

template < typename T,
  typename std::enable_if<
    std::is_pointer<T>::value
  >::type* = nullptr
>
void f( T ) {
  std::cout << "T is pointer" << std::endl;
}

と書く必要があるみたいです. ( nullptr(void*)0 でも可.)

とはいえ,この動作は C++0x で追加された機能*1であり, GCC では未だ使えない*2為,

今でも問題なく使える enabler を使うのが一番な気もします.

最新の GCC 4.7 で実装されました! これで enabler なんて おさらばです.

…まぁ,正直, typename std::enable_if<cond, int>::type = 0 なら,今でも使えるんですけどね.

*1:詳しくは本の虫の該当記事 http://cpplover.blogspot.com/2011/04/6c0x.html を参照のこと.

*2http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48582

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/gintenlabo/20110825/1314303669