id:iorateさんから指摘されて、regular()関数が出力する関数オブジェクトindirect_functorに対するboost::result_ofの特殊化で、boost::result_of
namespace boost { #if !defined(BOOST_RESULT_OF_USE_DECLTYPE) || defined(BOOST_NO_DECLTYPE) template <class F> struct result_of<boost::range::detail::indirect_functor<F>()> { typedef typename boost::result_of< typename boost::range::detail::indirect_functor<F>::indirected_functor_type() >::type type; }; template <class F> struct result_of<const boost::range::detail::indirect_functor<F>()> { typedef typename boost::result_of< typename boost::range::detail::indirect_functor<F>::indirected_functor_type() >::type type; }; #endif template <class F> struct tr1_result_of<boost::range::detail::indirect_functor<F>()> { typedef typename boost::tr1_result_of< typename boost::range::detail::indirect_functor<F>::indirected_functor_type() >::type type; }; template <class F> struct tr1_result_of<const boost::range::detail::indirect_functor<F>()> { typedef typename boost::tr1_result_of< typename boost::range::detail::indirect_functor<const F>::indirected_functor_type() >::type type; }; }
それと、C++11環境でas_containerを代入で使用すると、initializer_listとのオーバーロードで曖昧になってしまい、コンパイルエラーになる問題を修正しました。
#include <iostream> #include <vector> #include <boost/range/adaptor/filtered.hpp> #include <boost/range/experimental/as_container.hpp> bool is_odd(int x) { return x % 2 == 0; } int main() { const std::vector<int> v1 = {1, 2, 3, 4, 5}; std::vector<int> v2; v2 = v1 | boost::adaptors::filtered(is_odd) | boost::as_container; // これ for (int x : v2) { std::cout << x << std::endl; } }
2 4
対処の内容としては、テンプレートの型変換演算子で、関数テンプレートのデフォルトテンプレート引数を使用してinitiailzier_listをdisable_ifで弾くようにしました。
template <class> struct is_initializer_list : mpl::false_ {}; template <class T> struct is_initializer_list<std::initializer_list<T> > : mpl::true_ {}; template <class Range> class as_container_wrapper { Range range_; public: explicit as_container_wrapper(Range& range) : range_(range) {} #if !defined(BOOST_NO_INITIALIZER_LISTS) && !defined(BOOST_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS) template <class Container, class Enable = typename boost::disable_if<is_initializer_list<Container>>::type> operator Container() const { return Container(::boost::begin(range_), ::boost::end(range_)); } #else template <class Container> operator Container() const { return Container(::boost::begin(range_), ::boost::end(range_)); } #endif };
この対処の問題としては、initializer_listと関数テンプレートのデフォルトテンプレート引数が同時に使えなければ、initializer_listとの曖昧さを解決できないというのがあります。今後C++11対応するコンパイラが、関数テンプレートのデフォルトテンプレート引数より先にinitializer_listを実装してしまった場合に問題が起こります。
テンプレートの型変換演算子で、他にSFINAEする方法があればいいのですが、現状ではその方法が思いつきません。
また、以下のようなコンストラクタの()による呼び出しでは、as_containerのオーバーロードが曖昧でコンパイルエラーになってしまうという問題。
std::vector<int> v2(v1 | as_container); // error
oven::copiedのドキュメントによれば、どうやらGCCのバグらしいです。まだ詳しく調べてません。