ROS 2では、C++はC++11とC++14の一部、PythonはPython 3.5以上が採用されることになりました。 C++に関しては、C++17の正式リリースが済んで開発環境も整い次第、こちらも採用するという意欲的な態度を取っています。

そのため、ROS 2ユーザはC++03のこれまでのプログラミングスタイルから脱却する必要があります。 本日は、ROS 2のソースコードを読んでいて頻出するC++11, 14の言語仕様を列挙します。

参考文献

C++11, 14に関する書籍では、O'ReillyのEffective Modern C++が一番実践的な内容にまとまっていました。

Effective Modern C++ ―C++11/14プログラムを進化させる42項目
Scott Meyers
オライリージャパン
売り上げランキング: 21,157

その他、ウェブサイトでは以下のサイトがすべての言語機能を紹介していて、C++11の追加言語機能の多さに驚かされます。

autoキーワード

変数宣言時に具体的な型名の代わりにautoを指定することで、変数の型を初期化しから推論します。

auto i = 0;
auto result = some_method(1, 2, 3);

関数の返り値であったり、テンプレートを使ったときにコーディング量が減って効果を発揮します。 ただし、あまり多用するとソースコードを読む自分以外の人が何をやっているのか、意味を読み取るのが難しくなるので、ご注意を。

decltype

オペランドで指定した型を取得することができます。

int i = 0;
decltype(i) j = 1;

上記例ではdecltype(i)がコンパイル時にintに置き換わります。 autoと同様に、多用するとソースコードのリーダビリティを下げる可能性があります。

lambda式

関数オブジェクトをその場で定義します。 ROS 2のSubscriberのコールバック関数呼び出しに使うと便利です。

auto subscriber = this->create_subscription<:msg::int32>(
  input, [](std_msgs::msg::Int32::SharedPtr msg) {
    // Do something
}, rmw_qos_profile_default);

[]の部分をキャプチャと呼び、説明は省きますが、関数の外の変数へのアクセス方法を制御します。

std::unique_ptr, std::shared_ptr

リソースへのポインタの所有権を占有するものがunique_ptr、共有するものがshared_ptrです。 スマートポインタとも呼ばれます。 同じくC++11で導入されたムーブセマンティクスを組み合わせることで、C++98のauto_ptrが抱えていた問題を解決しました。

auto node1 = std::shared_ptr(new rclcpp::node::Node("some_node"));
auto node2 = rclcpp::node::Node::make_shared("some_node");

上記node1node2は、結果としてrclcpp::node::Nodeへのポインタを所有しているという意味では同じですが、メモリ割り当ての効率から、後者が推奨されています。

ROS 1でもBoostライブラリの同名の似た機能boost::shared_ptrを使って代用していましたが、完全に置き換わりました。

前述のstd_msgs::msg::Int32::SharedPtrのように、.msgのIDLで定義したメッセージは、ビルドするとメッセージ名::SharedPtrshared_ptrがエイリアスとして定義されます。

次回

今回は閑話休題的な話でしたが、これらの言語機能が読めれば、基本ROS 2のrclcppを使ったソースコードは読めるようになります。

明日からは、Turtlebot 2のROS 2対応版のソースコードを読みつつ、ラズパイマウスのROS 2対応を進めていきます。