C++ で std::regex を使った split

C++ で split が話題になっていたのでやってみた。

#include <regex>
#include <iostream>
#include <string>
#include <vector>

int
main(){
    auto split = [](std::string src, auto pat){
        std::vector<std::string> result{};
        std::regex reg{pat};
        std::copy(
            std::sregex_token_iterator{src.begin(), src.end(), reg, -1},
            std::sregex_token_iterator{},
            std::back_inserter(result)
        );
        return result;
    };

    std::string src{"homu,mami,mado"};

    for(auto&& str : split(src, ",")){
        std::cout << str << std::endl;
    }
    

    return 0;
}
/* output:
homu
mami
mado
*/

C++ で split のような関数を標準ライブラリにいれる場合、戻り値型をどうするのかがむずかしいよね…。

C++17 で追加された std::conjunction/std::disjunction メタ関数

知らなかったので覚書。
C++17 で std::conjunctionstd::disjunction という2つのメタ関数が追加されました。
この2つのメタ関数はいずれも可変長テンプレート引数を受け取ります。
具体的にどのようなメタ関数なのかは以下のコードを見てください。

#include <type_traits>

int
main(){
    using true_  = std::true_type;
    using false_ = std::false_type;

    // 引数型の ::value が全て true なら true
    static_assert( std::conjunction<true_, true_, true_>{}, "");
    static_assert(!std::conjunction<true_, false_, true_>{}, "");

    // 引数型の ::value のいずれかが true なら true
    static_assert( std::disjunction<true_, false_, false_>{}, "");
    static_assert(!std::disjunction<false_, false_, false_>{}, "");
    return 0;
}

std::conjunction は全ての型で && し、std::disjunction は全ての型で || するって感じですね。

どういう時に役立つの

例えば、『任意の複数の型が同じ型かどうか』を判定するメタ関数を定義するとします。
そういう場合は、std::conjunction を使えば簡単に処理する事が出来ます。

// 再帰みたいなことをしないでも実装できた!!
template<typename T, typename... Args>
struct all_of : std::conjunction<std::is_same<T, Args>...>{};

static_assert( all_of<int, int, int>{}, "");
static_assert(!all_of<int, int, float>{}, "");
static_assert(!all_of<int, int, int&>{}, "");

これは便利だなあ…。
ちなみに C++17 では fold expression を使って次のように実装することも出来たりします。

// std::conjunction すらいらない!!
template<typename T, typename... Args>
struct all_of : std::bool_constant<(... && std::is_same_v<T, Args>)>{};

static_assert( all_of<int, int, int>{}, "");
static_assert(!all_of<int, int, float>{}, "");
static_assert(!all_of<int, int, int&>{}, "");

C++14 で追加されればよかったのに…。

C++ のラムダ式を型推論しながら関数ポインタ型で受け取る

ほぼ使うことはないだろうけど、かなりの知見だったので覚書。

ラムダ式を関数ポインタ型へ変換する

これは割と一般的な知識だと思うんですが、『キャプチャしていない』ラムダ式は関数ポインタ型へとキャストする事が出来ます。

using func_t = int(*)(int);
// 関数ポインタ型として受け取る事が出来る
func_t twice = [](int n){ return n + n; };

+ 単項演算子で明示的に関数ポインタ型に変換する

さて、これを踏まえて次のように『関数ポインタ型を型推論する』ような関数にラムダ式を渡したいとします。

// テンプレートで戻り値型や引数型を推論するよ
template<typename R, typename A>
void
func(R(*f)(A)){
    
}

// error: no matching function for call to 'func'
func(
    [](int n){ return n + n; }
);

しかし、この場合は型変換されずにエラーになってしまいます。
こういう場合に + 単項演算子を使うことで明示的に関数ポインタ型に変換することが出来ます。

// テンプレートで戻り値型や引数型を推論するよ
template<typename R, typename A>
void
func(R(*f)(A)){
    
}

// ok
func(
    +[](int n){ return n + n; }
);

関数ポインタ型にキャスト出来ることは知っていたけど + 単項演算子で明示的に関数ポインタ型に変換できることは知らなかった…。
まあ実際に使う機会があるかどうかは別ですが…。

参照

ここがすごいよ Hsakell の $ 演算子

最近ちょろっと Haskell を書いてて 『$ 演算子すげー』ってなったので勢いでまとめてみる。
Haskell に明るくないのでゆるふわな感じで書いていくよー。
(ちなみに $ 自体の具体的な解説はしない。

関数適用と演算子の優先順位

他言語をやってから Haskell を学び始めると次のようなコードを書いてしまうことが多いと思う。

main = do
    -- 1 + 2 の結果を出力したいなっ
    print 1 + 2

しかし、上記のコードでは次のようなエラーになってしまう。

test.hs:3:16:
    No instance for (Num (IO ())) arising from a use of ‘+’
    In the expression: print 1 + 2
    In an equation for ‘main’: main = print 1 + 2

これは Haskell では『演算子よりも関数適用の優先順位が高い』ためである。
どういうことかというと括弧がない場合、 Haskell では以下のように解釈してしまうからである。

(print 1) + 2

つまり

  • 1 + 2 の結果を print に渡す

のではなくて

  • print 1 の結果を + 2 する

という処理になる。
こういう場合は括弧を使用して処理の優先順位を明示化して回避する必要がある。

main = do
    -- 先に 1 + 2 を処理するよ!
    print (1 + 2)

括弧の代わりに $ を使う

さて、括弧を使うことで回避することは出来た。
しかし、『いちいち括弧を書きたくない!!』というのが人の性でである。
そういう場合によく利用されているのが $ 演算子である。
この $ 演算子を使うことで次のようにして括弧を記述することなく適切に処理を行う事が出来る。

main = do
    -- 1 + 2 が先に処理されるよ!
    print $ 1 + 2

やったね!!これで括弧を書かなくてよくなったよ!!

$ 演算子の仕組みを解説

と、いうだけだと物足りないのでもう少し $ 演算子の仕組みについて解説。
先ほど『関数適用よ演算子よりも関数適用の優先順位が高い』とかいた。
なので

f 20 + f 10

みたいな処理は

(f 20) + (f 10)

のように『f 関数を先に適用してから』 + 演算子が呼び出されることになる。
これを別の視点から考えてみると演算子の『左辺』と『右辺』を先に処理するという風に解釈する事が出来る。
同様に + 演算子を $` 演算子に置き換えて考えてみると

f $ g 10

(f) $ (g 10)

のように処理される。
つまり $ 演算子を使うことで『左辺と右辺を別々に処理する』という事ができるようになるのである。
これにより $ 演算子で括弧を使わなくても処理の優先順位を制御することが出来ることになる。
ちなみに $ 演算子演算子の中で優先順位が低いので

print $ 1 + 2

(print $ (1 + 2))

となる。

まとめ

  • $ 演算子は処理の優先順位を制御できる
    • これにより括弧の記述を省略する事が出来る
  • Haskell において演算子よりも関数適用のほうが優先順位が高い
    • f a + g h(f a) + (g h) となる
  • 式が複雑になってくるなら素直に括弧を書こう

あと $ が具体的にどういう関数なのかはあえてここではかかないけど、気になったら調べてみてね!!

Ruby で内部クラスを private にする

Ruby で内部クラスを private にする場合どうするのがよいかと思っていたんですが private_constant を使うのがいいみたい。

class X
    class A
        
    end

    class B
        
    end
    private_constant :B

    def self.B_new
        B.new
    end
end

# OK
X::A.new

# Error: private constant X::B referenced (NameError)
# X::B

# OK
X.B_new

Ruby の hook メソッド一覧

Ruby から呼ばれる hook メソッドの一覧が欲しかったので Ruby 2.4 時点で定義されているメソッドをまとめてみました。
他にもあればコメント等で教えていただけると助かります。

Class クラス

  • #inherited
    • クラスのサブクラスが定義されたとき

Module クラス

  • #const_missing

    • 定義されていない定数を参照したとき
  • #extended

    • self が他のオブジェクト に Object#extend されたとき
  • #included

    • self が Module#include されたとき
  • #method_added

    • メソッド name が追加されたとき
  • #method_removed

    • メソッドが Module#remove_method により削除された時
  • #method_undefined

    • このモジュールのインスタンスメソッド name が Module#undef_method によって削除されるか、 undef 文により未定義にされるとき

BasicObject クラス

最新版の Vim で :terminal コマンドを使えるようにする

最近何かと話題の Vim:terminal ですが、使用する場合は最新版のソースコードからビルドする他にも configure 時に --enable-terminal を追加する必要があります。

$ ./configure --with-features=huge --enable-terminal

これで :terminal コマンドが使えるようになります。
細かいビルド方法などは以下のサイトを参考にしてください。