ゆとりーなの日記

日記的な事を書いて行くと思はれる

オブジェクト指向とは何ぞや

戻りビッ値先生のおかげですっかり敵性言語としてdisられる対象になってしまったRubyですが、今回はRubyっぽくC++のコンテナを回してみようという試みです。
うわさによるとRubyでは

[1, 2, 3].each do |i|
  puts i
end

で出来てしまうらしいのでC++でもそれっぽくしてやろうというわけです。

#include <iostream>
#include <array>
#include <vector>
#include <list>
#include <string>
#include <functional>
#include <boost/function_types/parameter_types.hpp>
#include <boost/type_traits/remove_extent.hpp>
#include <boost/type_traits/is_array.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/front.hpp>
#include <pstade/oven/algorithm.hpp>

namespace ngy313 {
template <typename Signature>
struct copy_argument {
  typedef
    typename std::remove_const<
      typename std::remove_reference<
        typename boost::mpl::front<
          typename boost::function_types::parameter_types<Signature>::type>::type
      >::type
    >::type
  type;
};

namespace detail {
template <typename Continer, typename Functor>
typename std::result_of<Functor(const Continer &)>::type operator |(const Continer &continer, const Functor &functor) {
  return functor(continer);
}

template <typename Functor>
class each_t {
 public:
  template <typename Signature>
  struct result {  
    typedef typename boost::mpl::if_<
      boost::is_array<typename copy_argument<Signature>::type>,
      typename const boost::remove_extent<typename copy_argument<Signature>::type>::type *,
      typename copy_argument<Signature>::type
    >::type type;
  };

  explicit each_t(const Functor &functor) : functor_(functor ) {}

  template <typename Continer>
  typename boost::mpl::if_<boost::is_array<Continer>, typename boost::remove_extent<Continer>::type *, Continer>::type 
  operator ()(const Continer &continer) const {
    pstade::oven::for_each(continer, functor_);
    return continer;
  }

 private:
  const Functor functor_;
};
}

using detail::each_t;

template <typename Functor>
each_t<Functor> each(const Functor &functor) {
  return each_t<Functor>(functor);
}
}

int main() {
  std::cout << "int array << std::endl;
  int a[3] = {0, 1, 2};
  a|ngy313::each([](const int i) {
    std::cout << i << std::endl;
  };

  std::cout << "std::vector<int>" << std::endl;
  std::vector<int> b;
  b.push_back(0);
  b.push_back(1);
  b.push_back(2);
  b|ngy313::each([](const int i) {
    std::cout << i << std::endl;
  });

  std::cout << "std::array<double, 3>" << std::endl;
  std::array<double, 3> c = {0.1, 1.2, 2.3};
  c|ngy313::each([](const double d) {
    std::cout << d << std::endl;
  });

  std::cout << "std::list<std::string>" << std::endl;
  std::list<std::string> d;
  d.push_back("Rubyより");
  d.push_back("C++が");
  d.push_back("好き");
  d|ngy313::each([](const std::string &s) {
    std::cout << s << std::endl;
  });

  return 0;
}
出力
int array
0
1
2
std::vector<int>
0
1
2
std::array<double, 3>
0.1
1.2
2.3
std::list<std::string>
Rubyより
C++が
好き

拡張メソッドの手法でeachを作ってやりました。なんとなくRubyっぽく書けてる気がします。タイプ数で圧倒的に負けてますが・・・。一応組み込み配列やSTLコンテナで使えるはずです。
まぁ内部ではfor_eachを使ってるわけですが、ここでオブジェクト指向の記法についての話が気になってきたので少し。
オブジェクト指向は個人的にオブジェクトに対してメッセージを送って何かやってもらうというイメージがあります。となると、C++のようにコンテナを回すのに関数にコンテナを渡して捜査やらなんやらするよりも、Rubyのようにコンテナのメソッドとして捜査するメドッドを呼び出したほうがオブジェクト指向っぽい表記なのかなという気がしないでもないです。という風にふと思っただけです。