Open6

C++入門

KatsukiniwaKatsukiniwa

AtCoder Problemsで練習していたが、そもそもC++の基礎知識があまりにも抜けており、茶色問題すら解けないという現実に直面したため、今までなんとなくで書いてきたC++をきちんと理解し、スニペットなども交えながらメモしていく。

KatsukiniwaKatsukiniwa

文字列Sに対してX文字目からY文字抽出する場合は

string T = S.substr(X, Y);

と実装する。

例えばある文字列Sをi文字目で分割する場合は

/**
 * 0番目からi文字抽出する
 */
string left = S.substr(0, i);

/*
 * i番目から最後までを抽出する
 */
string right = S.substr(i);

具体例

string name = "TomBrown";
string firstName = name.substr(0, 3);
string lastName = name.substr(3);
cout << "firstName: " << firstName << endl << "lastName: " << lastName << endl;
/*
 * 実行結果は以下のようになる
 * firstName: Tom
 * lastName: Brown
 */
KatsukiniwaKatsukiniwa

ある文字列SにアルファベットA~Zがそれぞれ何文字含まれているか探索する時は

string S = "aabcayyyy";
map<char, int> result;
for (char z = 'a'; z <= 'z'; z++) {
  result.insert({z, count(S.begin(), S.end(), z)});
}
/*
 * 実行結果は以下のようになる
 * a => 3
 * b => 1
 * ...
 * y => 4
 * z => 0
 */
KatsukiniwaKatsukiniwa

mapに要素を挿入する時は

#include <map>

int main() {
  /*
   * { "apple" => 2, "lemon" => 4 } を作りたい
   */
  map<string, int> bucket;

  bucket.insert({"apple", 2});
  bucket.insert({"lemon", 4});
  cout << bucket.at("apple") << endl; // 2
  cout << bucket.at("lemon") << endl; // 4

  /*
   * make_pairでmapに挿入するペアを作成できる
   * 型はautoで良いらしい
   */
  auto orange = make_pair("orange",14);
  bucket.insert(orange);
  cout << bucket.at("orange") << endl;
}

で実装する。
ペアを作成した時になぜ型をautoで書けるのか分かっていないので誰か教えて下さい...。

map内の要素を全て出力したい場合は

for (const auto&[key, value]: bucket) {
  cout << key << " => " << value << endl;
}
/*
 * 実行結果は以下のようになる
 * apple => 2
 * lemon => 4
 * orange => 14
 */
yaito3014yaito3014

まず、 C++ における auto は型推定のためのプレースホルダーです。
C++ は C言語 から構文や機能の多くを受け継いでおり、変数の宣言には int x;std::string s; などのように何かしらの型を書く必要があります。しかし、例えば TypeScript では let x = 42; のように型アノテーションが省略された宣言でも、変数を初期化する式の型から変数の型が推定されます。
C++ でも同じような機能を取り入れようとした結果、書かなければいけない型の場所に auto というキーワードを置くことで型の推定を行うことになりました。

次に、 std::make_pairという関数[1]は引数に渡された型に対応する std::pair を返すような関数になっています。

std::make_pair(42, 3.14);
// 引数の型 : int, double
// 戻り値の型 : std::pair<int, double>

std::string str = "C++";
std::make_pair('C', str);
// 引数の型 : char, std::string
// 戻り値の型 : std::pair<char, std::string>

std::make_pair の詳細については割愛しますが、TypeScript では次のようなものに相当します。

function make_pair<T, U>(x: T, y: U): [T, U] {
  return [x, y];
}

これらのことから、 auto p = make_pair("foo", 42); という変数宣言において make_pair("foo", 42) という関数呼び出しの結果は std::pair<std::string, int> に相当する型[2]であり、変数の型を明示しなくともその型として変数が宣言及び初期化されます。

脚注
  1. 厳密には関数テンプレートと呼ばれるものです ↩︎

  2. 実際には std::pair<const char*, int> になりますが、std::pair<const char*, int>std::pair<std::string, int> に変換できるため、 std::map<std::string, int> に対する insert は問題なく動作します。 ↩︎

KatsukiniwaKatsukiniwa

おお、ありがとうございます〜!
autoはc++側で型推論をいい感じにして欲しい時に使うのかな?と思いました。