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 で追加されればよかったのに…。