まず、C++11/14対応のEffective C++は、『Effective Modern C++』という名前になる予定です(略称は「EMC++」)。
現在、1回目のテクニカルレビューに入ったところで、発売は10月ころになるそうです。出版社はAddison-WesleyではなくO'Reillyです。
7月の第2週には、O'Reillyにリリースページができるそうです。
角度のstrong typedefは今まで、tagged_real
のサンプルコードとして提供していましたが、たまに使うのでライブラリ化しました。
例:
#include <iostream> #include <shand/angle.hpp> int main() { shand::degree_f deg(45.0f); shand::radian_f rad = shand::angle_cast<shand::radian_f>(deg); std::cout << rad.get() << std::endl; // shand::sin(deg); // compilation error shand::radian_f sin_result = shand::sin(rad); std::cout << sin_result.get() << std::endl; }
出力:
0.785398 0.707107
角度の単位を変換するには、angle_cast()
関数テンプレートを使用します。Chronoライブラリではミリ秒や秒といった単位間の変換を型昇格として表現していますが、ディグリーとラジアンの間には昇格の関係はないと判断し、関数を通して変換することにしました。
ディグリー(度数法)とラジアン(弧度法)の角度型は、以下のように定義しています:
namespace shand { struct degree_tag {}; struct radian_tag {}; template <class FloatingPoint> using degree_t = shand::tagged_real<FloatingPoint, degree_tag>; using degree_f = degree_t<float>; using degree_d = degree_t<double>; using degree_ld = degree_t<long double>; template <class FloatingPoint> using radian_t = shand::tagged_real<FloatingPoint, radian_tag>; using radian_f = radian_t<float>; using radian_d = radian_t<double>; using radian_ld = radian_t<long double>; }
degree_t
とradian_t
が、浮動小数点数型をパラメータにとる、tagged_real
のエイリアステンプレートで、_f
、_d
、_ld
が付いているものが、浮動小数点数型を設定済みのエイリアスになります。
その他、<cmath>
ヘッダで定義されている、いくつかの数学関数で、ラジアンを受け取ったり返したりする必要のあるものは、ラップして強い型付けにしています。
namespace shand { template <class FloatingPoint> radian_t<FloatingPoint> sin(const radian_t<FloatingPoint>& x) { return radian_t<FloatingPoint>(std::sin(x.get())); } ... template <class FloatingPoint> radian_t<FloatingPoint> atan2(const FloatingPoint& y, const FloatingPoint& x) { return radian_t<FloatingPoint>(std::atan2(y, x)); } }
非同期APIをラップして、リトライ処理を入れる。やってることは、エラーハンドラの関数オブジェクトをラップしてリトライ状態を持たせ、再帰的に非同期APIを呼んでいる。
#include <iostream> #include <string> #include <functional> void asyncApi(std::function<void(const std::string& data)> callback, std::function<void(const std::string& error)> errorF) { std::cout << "async api" << std::endl; errorF("error"); // callback("data"); } struct AsyncRetryFunctor { std::size_t retry_; std::function<void(const std::string& data)> callback_; std::function<void(const std::string& error)> errorF_; template <class Callback, class ErrorF> AsyncRetryFunctor(std::size_t retry, Callback callback, ErrorF errorF) : retry_(retry), callback_(callback), errorF_(errorF) {} void operator()(const std::string& error) { if (retry_ <= 0) { errorF_(error); } else { --retry_; asyncApi(callback_, *this); } } }; void asyncRetry(std::size_t retry, std::function<void(const std::string& data)> callback, std::function<void(const std::string& error)> errorF) { asyncApi(callback, AsyncRetryFunctor(retry, callback, errorF)); } int main() { asyncRetry( 3, [](const std::string& data) { std::cout << data << std::endl; }, [](const std::string& error) { std::cout << error << std::endl; } ); }
出力:
async api async api async api async api error
C++11の生文字列リテラル(Raw String Literals)を使うと、簡単なJSONをささっと書けて便利。文字列の中に何も考えずダブルクォートを書ける。
#include <iostream> #include <string> int main() { std::string json = R"({"user_id": 123, "name": "Akira"})"; std::cout << json << std::endl; }
出力:
{"user_id": 123, "name": "Akira"}
Boost.Formatと組み合わせる例:
#include <iostream> #include <string> #include <boost/format.hpp> int main() { std::string json = (boost::format(R"({"user_id": %1%, "name": "%2%"})") % 123 % "Akira" ).str(); std::cout << json << std::endl; }
これをクラステンプレート化した。
インタフェース:
namespace shand { template <class ValueType, class Enum> class special_value { public: using value_type = ValueType; using enum_type = Enum; special_value(); // initialize ValueType special_value(ValueType value); special_value(Enum e); special_value& operator=(ValueType value); special_value& operator=(Enum e); // どちらの値が入っているかの判定 bool has_value() const; bool has_enum() const; // 値の取り出し // それぞれの型の値が入っていない場合は、boost::bad_get例外を送出する ValueType& get_value(); const ValueType& get_value() const; Enum& get_enum(); const Enum& get_enum() const; // それぞれの型の値が入っていたときに指定された関数オブジェクトを呼び出す。 // 入っていなかったら関数オブジェクトを呼び出さない。 // *thisを返す。 template <class F> // void(ValueType& value) or void(ValueType& value) special_value& on_value(F f); template <class F> const special_value& on_value(F f) const; template <class F> // void(Enum value) or void(Enum& value) special_value& on_enum(F f); template <class F> const special_value& on_enum(F f) const; }; }
例:
#include <iostream> #include <shand/special_value.hpp> enum class PopType { Root }; std::string popToString(PopType) { return "Root"; } int main() { // size_tかPopTypeのどちらかの型の値が入る shand::special_value<std::size_t, PopType> pop_count = 1u; // pop_count = PopType::Root; // size_tの値が入っていたときの処理 pop_count.on_value([](std::size_t value) { std::cout << value << std::endl; }) // PopTypeの値が入っていたときの処理 .on_enum([](PopType pop) { std::cout << popToString(pop) << std::endl; }); }
出力:
1
実装はboost::variant
のラッパー。設計は、expected
を参考にした。クラス名はこれでいいのか、まだ悩み中。もしかしたら変えるかも。
switch (and other control flow) as expressions? - Rust inspired
switch
文でこんな感じに値を返したいな!という話。
auto x = switch (something) { case FOO: break 1; case BAR: break 2; default: break 3; }
auto x = [&]{ switch (something) { case FOO: return 1; case BAR: return 2; default: return 3; }}();
ソートするときに、左辺と右辺を比較するラムダ式を書くのがめんどくさいので、「どの要素を比較対象とするか」だけを書きたい、という目的のためのラッパー、order_by
。
template <class F> struct OrderBy { F f; template <class T> bool operator()(const T& x, const T& y) const { return f(x) < f(y); } }; template <class F> OrderBy<F> order_by(F f) { return {f}; } #include <iostream> #include <vector> #include <string> #include <algorithm> int main() { std::vector<std::pair<int, std::string>> v = { {3, "Alice"}, {1, "Bob"}, {4, "Carol"} }; // firstをキーにして並び替え std::sort(v.begin(), v.end(), order_by([](auto x) { return x.first; })); for (const auto& x : v) { std::cout << x.first << std::endl; } }
出力:
1 3 4
前に全く同じのを書いた気がする。
order_by
という名前はデータベースっぽすぎる気もするので、もうちょっと考えた方がいいかもしれない。そんなこともないかもしれない。
@cpp_akira compare_on とか less on とか(参考: http://t.co/WEmhKtJSBH )
— めるぽん(直角クランクマン) (@melponn) 2014, 6月 12
@cpp_akira Python だと key とか keyfunc と呼びますね。遅いPython関数の呼び出し回数を n log n から n にできるので高速化効果もある。 / http://t.co/jl1hxSRmo0
— INADA Naoki (@methane) 2014, 6月 12
C++14で導入されるdecltype(auto)
を使うと、return
とreturn (…)
で戻り値の型が変わる。前者は値、後者は参照となる。
decltype(auto) f() { static int value = 3; return value; } decltype(auto) g() { static int value = 3; return (value); } int main() { int f_result = f(); int& g_result = g(); }