蒼い夏の空のライブラリー

ブログ名は適当に考えました  このブログの記事のすべてはCC0、パブリックドメインです

ポエム

std::forward

std::forward は、関数テンプレートであるにも関わらずテンプレート引数を指定する必要があります。しかし、テンプレート引数はだいたい std::forward<decltype(a)>(a) のような感じで書くと思います。個人的に、これは std::forward をラップして、

// You can write forward without template argument.
template <typename T>
[[nodiscard]] constexpr T && forward(T && arg) noexcept
{
   return std::forward<decltype(arg)>(arg);
}

のようにしておけば、forward(arg) のようにテンプレート引数の指定なしで書けるのでいいのではないかと思っています。

[追記]と、思っていた時期もあったのですが、どうやらダメみたいです... ↓参照

c++ - Why is template argument deduction disabled with std::forward? - Stack Overflow

命名規則

キャメルケース、スネークケースなどがありますが、個人的には全部小文字のスネークケースがよいのではないかと思います。なぜなら、全部小文字の場合にはフォーマッタなどでキャメルケースなどに変換することが容易だからです。型は大文字、などとして大文字小文字で区別すると、SomeType sometype;のように単純に小文字に変換することができない場合があります。その点、型も変数も小文字で統一すると、このようなことがなくスムーズに命名規則を変換できがちです。

また、クラスのプライベートメンバを m_ から始まるようにすると、コード補完が効いて便利です。_ 始まりだとグローバルにある標準の関数が大量にリストアップされます... 末尾は _ をつけてもつけなくても変わらないと思います。つけたほうがちょっとかっこいいかもしれません。(個人の感想です...)

コメント

コメントを書くときに日本語で書くと絶対に文字化けします。これは真理です。

書くことがなさすぎるので、自作ライブラリの紹介をします

初めに

このブログは作ってみたものの、特に書くこともなく放置していました() なので、いつか書こうと思っていた自作ユーティリティーのドキュメントなどを書こうと思います。

nyaruga::util::diff

今回は、関数を微分する関数を紹介します。nyaruga::util::diff です。

nyaruga_util/diff.hpp at master · alphya/nyaruga_util · GitHub

using num_t =
   boost::multiprecision::number<boost::multiprecision::cpp_dec_float<1000>>;

// 微分します
// 7 点近似です
template <typename Number = num_t, typename F>
constexpr auto diff(F && f) noexcept
{
   return [f](auto && x) noexcept(noexcept(f(x))) -> Number {
      auto h = 1e-7;
      if constexpr (std::is_same_v<Number, num_t>)
         h = DBL_EPSILON;

      auto&& y1 = f(static_cast<Number>(x + h));
      auto&& y2 = f(static_cast<Number>(x - h));
      auto&& y3 = f(static_cast<Number>(x + 2 * h));
      auto&& y4 = f(static_cast<Number>(x - 2 * h));
      auto&& y5 = f(static_cast<Number>(x + 3 * h));
      auto&& y6 = f(static_cast<Number>(x - 3 * h));

      return (y5 - 9 * y3 + 45 * y1 - 45 * y2 + 9 * y4 - y6) /
                           (60 * h);
   };
}

上記の関数は、一引数の関数を引数にとって、「点xでの微分係数を返すような関数」を返す高階関数です。7 点近似らしいです。導出などは、検索すればおそらく見つけられると思われます() (自分でも、これでよいのかわかってないです。もっと良いやり方をご存じの方は教えてください...orz)

ちなみに、h の値も雰囲気で決定しました☆orz

使い方

int main()
{
   auto fn = [](double x){ return std::pow(x, 2); };

   // テンプレート引数は、関数の引数の型などに合わせてください
   auto d_fn_d_x = diff<double>(fn);
   
   std::cout << d_fn_d_x(3); // 6
}

nyaruga::util::partial_diff

せっかくなので、偏微分する関数も紹介します。

nyaruga_util/partial_diff.hpp at master · alphya/nyaruga_util · GitHub

namespace hana = boost::hana;

// Partial differentiation
template <std::size_t count, typename NumType = num_t, typename F>
constexpr auto partial_diff(F && f) noexcept
{
   return [f](auto&& ... args) noexcept -> NumType
   {
      return diff<NumType>(bind_select_arg_replace<count>(forward(f), args...))
         (hana::arg<count>(forward(args)...));
   };
}

テンプレート引数 count で、( 1 からスタートして)何番目の引数に関して偏微分するかを指定します。 bind_select_arg_replace<count>は、count で指定した引数をプレースホルダーにするように、与えられた引数を引数の関数に束縛するような高階関数です。こうして一引数関数を作り、diff関数でその引数に関して微分しています。

使い方

int main()
{
   auto lambda = [](auto ... a) { return static_cast<nyaruga::util::num_t>((a * ... )); };
   std::cout << std::setprecision(18) 
      << nyaruga::util::partial_diff<1>(lambda)(nyaruga::util::num_t(2), 5., 6.); // 30
}

おわりに

すごく手抜き気味になってしまいましたが、たぶんこの記事は誰も見ないと思って公開しようと思います...

std::string を空白で分割する

std::sregex_token_iterator を使う

例として、

双方向連結リスト | アルゴリズムとデータ構造 | Aizu Online Judge

をやった

#include <iostream>
#include <list>
#include <string>
#include <regex>
#include <algorithm>

class my_list : public std::list<int>
{
    std::regex m_separator{" "}; // 分割用のセパレータ
public:
    using std::list<int>::list; // std::listのコンストラクタ群のmy_listでの暗黙定義
    void accept_command(const std::string & line)
    {
        // セパレータで入力を分割し、イテレータ it で参照できるようにしています
        auto && it = std::sregex_token_iterator(std::begin(line), std::end(line), m_separator, -1);

        // コマンドを command に入れています
        const std::string & command = *it;

        if (command == "insert")
        {
            // コマンドの数字を num に入れています
            auto && num = std::stoi(*std::next(it));
            emplace_back(num);
        }

        else if (command == "delete")
        {
            auto && num = std::stoi(*std::next(it));
            erase(std::find_if(begin(), end(),
                [&num](auto && tmp) {return tmp == num; }));
        }

        else if (command == "deleteFirst") pop_front();

        else if (command == "deleteLast") pop_back();

        else std::cout << "コマンド名をチェックしてください";
    }
};

template<typename T>
void show(T && tmp)
{
    for (auto && i = tmp.rbegin(); i != tmp.rend(); ++i)
    {
        std::cout << *i;
        if (i != std::prev(tmp.rend())) std::cout << " ";
    }
}

int main()
{
    std::string s;
    std::getline(std::cin, s);

    const int & line_num = stoi(s);

    my_list m;
    for (auto i = 0; i < line_num; ++i) 
    {
        std::getline(std::cin, s);
        m.accept_command(s);
    }

    show(m);
}

C++ とても長い変数宣言

長い誰の役にも立たない変数宣言をしただけ

#include <iostream>

template <typename T> 
[[maybe_unused]] 
volatile static const constexpr
unsigned long long int ***** 
a = static_cast<const volatile long long unsigned int*****>(0);

int main()
{   
    std::cout << a<void> << "\n";  // 0
}