2012年9月4日火曜日

Variadic Template にまつわる Workaround

C++11 は確かに便利、なのだが現状はまだ実装が十分と言えず回避手段(workaround)を取らざるを得ない場合がある。の割には余りそういう説明を見ない、ということでせっかく書いたのでメモってみる。まぁ Boost のソースコードの中にたくさん埋まっているのだろうし、ひょっとしたら C++er は息をするように workaround が書ける人種なのかもしれないが、そこはそれ。

sorry, unimplemented: use of ‘type_pack_expansion’ in template

#include <utility>
struct B { int operator()(int n) const { return n; } };

template<typename C>
struct A {

#if __GNUC__ == 4 && (__GNUC_MINOR__ <= 5 || __GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ == 0)

  template<typename ... Args>
  struct deduce {
      typedef decltype(C()(std::declval<Args&&>()...)) type;
  };
  template<typename ... Args>
  typename deduce<Args...>::type operator()(Args && ... args) const
  { return C()(std::forward<Args>(args)...); }

#else

  template<typename ... Args>
// sorry, unimplemented: use of ‘type_pack_expansion’ in template
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48292
  auto operator()(Args && ... args) const -> decltype(C()(std::forward<Args>(args)...))
  { return C()(std::forward<Args>(args)...); }

#endif
};

このエラーメッセージが出るのは恐らくこの場合には限らないと思うのだが、type pack (Args ... みたいな展開)を tailing return type 中で使った場合。GCC bugzilla にも書いてある通り、別のクラスに切り出すことで回避できる。@iorate さんの記事([C++][Boost] C++ で一般化された on を書く)にも workaround の方法を含め書かれている。後は、GCC 4.6.1 から直っている、という情報くらいだろうか。

sorry, unimplemented: cannot expand ‘Args ...’ into a fixed-length argument list

#include <boost/fusion/include/vector.hpp>

#include <boost/fusion/adapted/mpl.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include "variadic_bridge.hpp"

template<typename ... Args>
struct C {

#if __GNUC__ == 4 && __GNUC_MINOR__ <= 6

  typename boost::fusion::result_of::as_vector<
    typename yak::util::variadic_to_vector<Args...>::type
  >::type v;

#else

// sorry, unimplemented: cannot expand ‘Args ...’ into a fixed-length argument list
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
  boost::fusion::vector<Args...> v;

#endif
};

こっちはエラーメッセージを日本語対象でググっても合っているものは tweet 1件しかヒットしない。……みんな困ってそうなものなのだが。variadic な template parameter を非 variadic な template に渡せない、というものだ。自作ヘルパ variadic_bridge.hpp を使って variadic な template parameter を MPL vector に変換して、さらに boost::fusion::vector に変換している。まぁ MPL vector まで持って来られれば後はどうとでもなるとは思うが、一応、固定長引数として Metafunction Class に渡す variadic_to_fixed も用意はしてある。こっちは GCC 4.7.0 から修正。

まとめ?

そもそも VC は 2012 でも variadic template 対応してねーよ、という時点で PP するしかないという話なのが悲しいところ。

しかし、CSS はブラウザバグとその対処、みたいなものが結構見つかるのだが C++ についてはそういうまとめみたいなものはないのだろうか。

0 件のコメント:

コメントを投稿