LoginSignup
1
1

More than 5 years have passed since last update.

PythonのコードをC++98に移植して感じたこと。

Last updated at Posted at 2015-02-02

Pythonでは簡潔に記述できる事でも、C++98では膨大なテンプレコードを書く必要があります。参考に(?)C++とPythonのコードを並べてみました。

一言でいうと「シンタックスシュガーと動的型付けってすばらしい」

(書きかけなので、今後項目が増えるかもしれません)

その1 静的型付け/動的型付け

Point get_distance(const Point& point1, const Point& point2) {
  return sqrt( pow(point1.x - point2.x, 2) + pow(point1.y - point2.y, 2);
}
def get_distance(point1, point2):
  pt1_x, pt1_y = point1
  pt2_x, pt2_y = point2
  return math.sqrt((pt1_x - pt2_x) ** 2, (pt1_y - pt2_y) ** 2)

C++:型に加えconst、*やら&、テンプレートといった修飾子などが煩わしい。(入出力が明示かされたり、コンパイル時の構文チェックは助かるけども・・・)
Python:動的型付けなので、型定義が不要。型は変数ではなく値が持つ.

その2 リストとディクショナリ

vector<double> calculate(const vector<Line>& lines) {
  vector<double> result;
  vector<Line>::const_iterator ite = lines.begin();
  while( ite != lines.end() ) {
    double value = 何かする(*ite);
    result.push_back(value);
    ++ite;
  }
  return result;
}
def calculate(lines):
  result = [] // []でリスト形式, {}だとディクショナリ.
  for line in lines:
    value = 何かする(line)
    result.append(value)
  return result

C++: C++98では、シンタックスシュガーなし(C++11はシンタックスシュガー有り)。

python: オブジェクトの生成、要素へのアクセス、ループにシンタックスシュガー有り。上のケースはリスト内包表記を使うとさらに簡潔に記述できる。

def calculate(lines):
  result = [ 何かする(line) for line in lines]
  return result

その3 タプル


void foo() {
  Point pt1(0,1);
  Point pt2(0,5);
  Line line(pt1, pt2);

  double score;
  double distance;
  calculate(line, &score, &distance); 
  ...
}

void calculate(const Line& line, double* out_score, double* out_distance) {
  *out_distance = get_distance(line.point1, line.point2);
  *out_score = get_score(line);
}

double get_distance(const Point& pt1, const Point& pt2) {...}


def foo():
  pt1 = (0,1)
  pt2 = (0,5)
  line = (pt1, pt2)
  distance, score = caclculate(line)
  ...

def calculate(line):
  distance = get_distance(*line)
  score = get_score(line)
  return distance, score

def get_distance(pt1, pt2):
  ...

C++:値をまとめたいときは、汎用のpairを使うか、PointやLineのように構造体/クラスを定義する必要がある。これも構文チェックとのトレードオフ。

Python:タプルを使えば、ちょっとしたペアを引数に渡したいときに重宝します。使いすぎると、可読性が下がる。

その4 ラムダ式

void foo(const Line& line, double x) {
  double y1 = func(line, x);
  double y2 = func(line, x+1);
}

// 直線line上のxに対応するy座標を求める.
// ※:y=1やx=0といった線は考慮しない.
double func(const Line& line, double x) {
   // 傾き取得
   double slope = get_slope(line.point1, line.point2);
   double const_value = get_const_value(line.point1, slope);
   double y = x * slope + c;
   return y;
}

def foo(line, x):
  func = get_func(line)
  y1 = func(x)
  y2 = func(x + 1)

def get_func(line):
  slope = get_slope(*line)
  const_value = get_const_value(line[0], slope)
  return (lamda x: x * slope + c)

pythonではラムダ式が提供されているので、ちょっとした事が簡単に記述できるようになります。
C++ならクラスを書けば、再利用性は上がるけど書くための敷居が高い。

その5 関数呼び出し

タプルやリストを自動的に個別の引数に展開してくれたり、名前付き引数できたりと楽ができます。

例: C++の関数のオーバーロードを減らす。

doule get_distance(const Point& pt1, const Point pt2) {
   return //演算結果
}

double get_distance(const Line& line) {
  return get_distance(line.point1, line.point2);
}
def get_distance(point1, point2):
  return ...

def foo(line):
  get_distance(*line) // lineがタプルかシーケンスなら自動的にpoint1, point2に展開してくれる.
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1