Qiitaからの移植です。
はじめに
C++のheader-onlyライブラリを作りたくなったので、試しに作ってみました。 https://github.com/h6ak/h6ak-cpp で公開しています。
ライブラリのコンセプトは特になくて、実装したくなったものをどんどん追加していく感じでやっています。まだしょうもないものしか作っていませんが、実装に当たって気を付けたことを2点述べたいと思います。
ADL対策
ADL(Argument Dependent Lookup; 実引数依存の名前探索)とは、関数の名前解決をする際に、実引数の型が定義されている名前空間で関数を探索する、という仕組みです。詳しい解説は
- ARGUMENT DEPENDENT LOOKUP (闇夜のC++)
- C++ ADLとは|問題と危険性、回避方法(明示的回避と事前回避) (MaryCore)
等に書かれています。
この仕様が思わぬ挙動を引き起こしかねないので、ADL対策を行いました。対策方法は、先ほど挙げたMaryCoreの記事の「ADLの回避(事前回避)」を参考にしました。
では、実際に自分が書いたコードで対策法を説明したいと思います。
namespace h6ak { namespace util_ { // to avoid ADL // like Python len function template <class T> std::size_t len(const T& obj) { return obj.size(); } // like Python in operator // "exist(k, t)" means "k in t" in Python template <class Key, class Container> bool exist(const Key& k, const Container& c) { auto result = std::find(c.begin(), c.end(), k); return result != c.end(); } } //util_ using namespace util_; } //h6ak
自作のライブラリではh6ak
という名前空間を定義し、外からはh6ak::function()
の形で呼び出せるようにしたいと思っています。自作ライブラリは将来的には色んなものを詰め込んだ雑多なものになると思われるので、ADLで予期せぬ名前解決が起きる可能性が出てきます。
そこで名前空間のh6ak
の下に名前空間を作り、名前解決の際の探索範囲を狭い範囲に限定させます。上のコードではutil_
という名前空間を定義しました。そして、h6ak::function()
の形で呼び出せるようにするために、using namespace util_;
という一文を追加しました。
ユニットテスト
ライブラリが想定通りの動作をすることを確認するには、ユニットテストがあると安心です。ユニットテストにはGoogle Testというフレームワークを使いました。なぜGoogle Testを採用したかと言うと、
- 職場で使用しているので慣れている
- 機能が充実している
- main関数を書かなくて済む
- CMakeと親和性があり、CLion使いには嬉しい
という理由からです。
私の自作ライブラリを導入してもらう際には、サードパーティのライブラリをあらかじめ導入する必要がないようにしたい、という思想があるので、Google TestはCMakeでダウンロード、セットアップできるようにしました。
CMakeList.txtの書き方は、Google Testの公式ドキュメントの「Incorporating Into An Existing CMake Project」を参考にしました。
また、Google Testによるテストコードを検出するために、cmakeのGoogleTestテストモジュールのgtest_discover_tests
を使用しました。詳しくはこちらです。gtest_discover_tests
は、CMakeのバージョンが3.10以上でないと使えないことに注意してください。
最後に
C++歴X年のC++初心者なので、お手柔らかにお願いします。