Boost C++ 函式庫

...世界上最受推崇和設計精良的 C++ 函式庫專案之一。 Herb SutterAndrei Alexandrescu,《C++ 編碼標準

概述

Mp11 是一個 C++11 元編程函式庫,用於在編譯時操作包含型別的資料結構。它基於樣板別名和可變參數樣板,並實作了「簡單 C++ 元編程」一文和其續篇中概述的方法。強烈建議在繼續閱讀本文檔之前先閱讀這些文章。

Mp11 建立的通用原則是,演算法和元函式是 F<T…​> 形式的樣板別名,而資料結構是 L<T…​> 形式的列表,函式庫對 L 沒有任何要求。mp_list<T…​> 是內建的列表型別,但 std::tuple<T…​>std::pair<T1, T2>std::variant<T…​> 也都是完全合法的列表型別,當然,由於 std::pair<T1, T2> 恰好有兩個元素,因此無法調整大小,因此無法與需要新增或移除元素的演算法搭配使用。

這種方法的另一個顯著特點是,列表 (L<T…​>) 與元函式 (F<T…​>) 的形式相同,因此可以像這樣使用。例如,透過 mp_transform<std::add_pointer_t, std::tuple<int, float>>std::add_pointer_t 應用於列表 std::tuple<int, float> 會得到 std::tuple<int*, float*>,但我們也可以將 mp_list 應用於相同的元組

using R = mp_transform<mp_list, std::tuple<int, float>>;

並得到 std::tuple<mp_list<int>, mp_list<float>>

定義

列表是 — 通常但不一定會是可變參數 — 樣板類別,其參數都是型別,例如 mp_list<char[], void>mp_list<>std::tuple<int, float, char>std::pair<int, float>std::shared_ptr<X>

元函式是類別樣板或樣板別名,其參數都是型別,例如 std::add_pointer_tstd::is_constmp_secondmp_push_frontmp_liststd::tuplestd::pairstd::shared_ptr,或是

template<class...> using F1 = void;

template<class T> using F2 = T*;

template<class... T> using F3 = std::integral_constant<std::size_t, sizeof...(T)>;

引用元函式是一個類別,其具有一個名為 fn 的公有元函式成員,例如

struct Q1 { template<class...> using fn = void; };

struct Q2 { template<class T> using fn = T*; };

struct Q3 { template<class... T> using fn =
  std::integral_constant<std::size_t, sizeof...(T)>; };

整數常數型別是一個類別,其具有一個公有成員 value,在 C++ 的意義上,它是一個整數常數。例如,std::integral_constant<int, 7>,或是

struct N { static int constexpr value = 2; };

集合是一個元素唯一的列表。

映射是一個列表的列表,內部列表至少有一個元素(索引鍵)。映射的索引鍵必須是唯一的。例如,

using M1 = std::tuple<std::pair<int, int*>, std::pair<float, float*>,
    std::pair<void, void*>>;

using M2 = mp_list<mp_list<int, int*>, mp_list<float>,
    mp_list<char, char[1], char[2]>>;

值列表是一個樣板類別,其參數都是值(非型別樣板參數)。值列表與 template<auto…​> class L 相符,並且需要 C++17(因為 auto 樣板參數是 C++17 的功能)。

值列表僅由少數幾個基本型別支援。Mp11 的主要重點在於型別操作。對於處理值列表,常用的方法是使用 mp_rename 將值列表轉換為型別列表,操作型別列表,然後使用 mp_rename_v 轉換回值列表。

範例

產生測試案例

假設我們已經編寫了一個元函式 result<T, U>

template<class T> using promote = typename std::common_type<T, int>::type;

template<class T, class U> using result =
    typename std::common_type<promote<T>, promote<U>>::type;

該元函式應該表示對整數型別 TU 進行算術運算的結果,例如 t + u。我們想要測試 result<T, U> 是否為 TU 的各種組合提供正確的結果,因此我們編寫了函式

template<class T1, class T2> void test_result()
{
    using T3 = decltype( T1() + T2() );
    using T4 = result<T1, T2>;

    std::cout << ( std::is_same<T3, T4>::value? "[PASS]": "[FAIL]" ) << std::endl;
}

然後需要多次呼叫它

int main()
{
    test_result<char, char>();
    test_result<char, short>();
    test_result<char, int>();
    test_result<char, unsigned>();
    // ...
}

手動編寫所有這些型別組合既笨拙又容易出錯,而且最糟糕的是,很無聊。這就是我們如何利用 Mp11 來自動化這項任務

#include <boost/mp11.hpp>
#include <boost/core/demangle.hpp>
#include <type_traits>
#include <iostream>
#include <typeinfo>

using namespace boost::mp11;

template<class T> std::string name()
{
    return boost::core::demangle( typeid(T).name() );
}

template<class T> using promote = typename std::common_type<T, int>::type;

template<class T, class U> using result =
    typename std::common_type<promote<T>, promote<U>>::type;

template<class T1, class T2> void test_result( mp_list<T1, T2> const& )
{
    using T3 = decltype( T1() + T2() );
    using T4 = result<T1, T2>;

    std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " )
        << name<T1>() << " + " << name<T2>() << " -> " << name<T3>()
        << ", result: " << name<T4>() << std::endl;
}

int main()
{
    using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
    tuple_for_each( mp_product<mp_list, L, L>(), [](auto&& x){ test_result(x); } );
}

它是如何運作的?

mp_product<F, L1, L2> 會呼叫 F<T1, T2>,其中 T1 會遍歷 L1 的所有元素,而 T2 會遍歷 L2 的所有元素,就像執行兩個巢狀迴圈一樣。然後它會回傳這些結果的列表,其類型與 L1 相同。

在我們的例子中,兩個列表都是相同的 std::tuple,而 Fmp_list,因此 mp_product<mp_list, L, L> 會得到 std::tuple<mp_list<char, char>, mp_list<char, short>, mp_list<char, int>, …​, mp_list<unsigned long, long>, mp_list<unsigned long, unsigned long>>

接著,我們對這個 tuple 進行預設建構,並將它傳遞給 tuple_for_eachtuple_for_each(tp, f) 會對每個 tuple 元素呼叫 f;我們使用 (C++14) lambda 函式來呼叫 test_result

在純 C++11 中,我們無法使用具有 auto&& 參數的 lambda 函式,因此我們必須將 test_result 設為具有樣板化的 operator() 的函式物件,並將其直接傳遞給 tuple_for_each

struct test_result
{
    template<class T1, class T2> void operator()( mp_list<T1, T2> const& ) const
    {
        using T3 = decltype( T1() + T2() );
        using T4 = result<T1, T2>;

        std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " )
            << name<T1>() << " + " << name<T2>() << " -> " << name<T3>()
            << ", result: " << name<T4>() << std::endl;
    }
};

int main()
{
    using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
    tuple_for_each( mp_product<mp_list, L, L>(), test_result() );
}

編寫 common_type 特化

標準特徵 std::common_type 用於取得一個類型,其所有引數都可以在不造成不必要精度損失的情況下轉換為該類型,當其預設實作(基於三元 ?: 運算子)不適用時,可以由使用者進行特化。

讓我們為兩個 std::tuple 引數撰寫 common_type 特化。為此,我們需要一個元函式,將 std::common_type 應用於每一對元素,並將結果收集到一個 tuple 中。

template<class... T> using common_type_t =
    typename std::common_type<T...>::type; // standard in C++14

template<class Tp1, class Tp2> using common_tuple =
    mp_transform<common_type_t, Tp1, Tp2>;

然後特化 common_type 來使用它。

namespace std
{

    template<class... T1, class... T2>
    struct common_type<std::tuple<T1...>, std::tuple<T2...>>:
        mp_defer<common_tuple, std::tuple<T1...>, std::tuple<T2...>>
    {
    };

} // std

(對於超過兩個引數,不需要特化 std::common_type — 它會從二元的情況處理合成適當的語義。)

這裡的微妙之處在於使用 mp_defer。我們可以定義一個巢狀的 typecommon_tuple<std::tuple<T1…​>, std::tuple<T2…​>>,它仍然可以在所有有效的情況下運作。然而,透過讓 mp_defer 定義 type,我們使我們的特化成為SFINAE友善的。

也就是說,當我們的 common_tuple 導致替代失敗而不是硬性錯誤時,mp_defer 將不會定義巢狀的 type,而定義為 typename common_type<…​>::typecommon_type_t 也會導致替代失敗。

作為另一個範例,考慮假設的類型 expected<T, E…​>,它表示成功回傳一個 T 的值,或是不成功回傳一個錯誤碼,其類型在列表 E…​ 中。expected<T1, E1, E2, E3>expected<T2, E1, E4, E5> 的共同類型是 expected<common_type_t<T1, T2>, E1, E2, E3, E4, E5>。也就是說,可能的回傳值會合併為它們的共同類型,而我們會取錯誤類型集合的聯集。

因此,

template<class T1, class E1, class T2, class E2> using common_expected =
    mp_rename<mp_push_front<mp_unique<mp_append<E1, E2>>, common_type_t<T1, T2>>,
        expected>;

namespace std
{

    template<class T1, class... E1, class T2, class... E2>
    struct common_type<expected<T1, E1...>, expected<T2, E2...>>:
        mp_defer<common_expected, T1, mp_list<E1...>, T2, mp_list<E2...>>
    {
    };

} // std

在這裡,我們採取了不同的方法;我們沒有將 expected 類型傳遞給 common_expected,而是傳遞 T 類型和 E 類型的列表。這使我們的工作更容易。mp_unique<mp_append<E1, E2>> 為我們提供了 E1E2 的串接,並刪除了重複項;然後我們透過 mp_push_frontcommon_type_t<T1, T2> 新增到前端;最後,我們將結果的 mp_list mp_renameexpected

修正 tuple_cat

文章 簡單的 C++11 元程式設計 建構了標準函式 tuple_cat 的實作,最終結果如下所示

template<class L> using F = mp_iota<mp_size<L>>;

template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
    return R{ std::get<Ks::value>(std::get<Is::value>(tp))... };
}

template<class... Tp,
    class R = mp_append<std::tuple<>, typename std::remove_reference<Tp>::type...>>
    R tuple_cat( Tp &&... tp )
{
    std::size_t const N = sizeof...(Tp);

    // inner

    using list1 = mp_list<
        mp_rename<typename std::remove_reference<Tp>::type, mp_list>...>;

    using list2 = mp_iota_c<N>;

    using list3 = mp_transform<mp_fill, list1, list2>;

    using inner = mp_apply<mp_append, list3>;

    // outer

    using list4 = mp_transform<F, list1>;

    using outer = mp_apply<mp_append, list4>;

    //

    return tuple_cat_<R>( inner(), outer(),
        std::forward_as_tuple( std::forward<Tp>(tp)... ) );
}

然而,此函式並非完全正確,因為它並未正確處理某些情況。例如,嘗試串連包含只能移動的元素(例如 unique_ptr)的 tuple 會失敗

std::tuple<std::unique_ptr<int>> t1;
std::tuple<std::unique_ptr<float>> t2;

auto result = ::tuple_cat( std::move( t1 ), std::move( t2 ) );

嘗試串連 const tuple 會失敗

std::tuple<int> const t1;
std::tuple<float> const t2;

auto result = ::tuple_cat( t1, t2 );

最後,標準 tuple_cat 被指定可在任意的 tuple 類型的類型上運作(也就是說,所有支援 tuple_sizetuple_elementget 的類型),而我們的實作僅適用於 tuplepair。例如,std::array 會失敗

std::array<int, 2> t1{ 1, 2 };
std::array<float, 3> t2{ 3.0f, 4.0f, 5.0f };

auto result = ::tuple_cat( t1, t2 );

讓我們逐一修復這些問題。如果知道在哪裡尋找,支援只能移動的類型很容易。問題在於我們傳遞給輔助函式 tuple_cat_Tp(正確地)是 tuple<unique_ptr<int>&&, unique_ptr<float>&&>,但是 std::get<0>(tp) 仍然會回傳 unique_ptr<int>&,因為 tp 是一個左值。此行為有點令人驚訝,但目的是防止不經意地重複移動。

長話短說,我們需要在 tuple_cat_ 中使用 std::move(tp) 來使 tp 成為右值。

template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
    return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
}

接下來,是 const 修飾的 tuple。這裡的問題在於,我們正在從輸入的 tuple 中剝離參考,而不是 const。因此,我們正在嘗試使用 Mp11 演算法來操作諸如 tuple<int> const 之類的類型,而這些類型不符合列表的概念。我們只需要剝離修飾詞,方法是定義標準函式庫中莫名其妙地遺失的有用基本類型 remove_cv_ref

template<class T> using remove_cv_ref = typename std::remove_cv<
    typename std::remove_reference<T>::type>::type;

然後在 remove_cv_ref<Tp> 中使用,而不是 typename std::remove_reference<Tp>::type

template<class... Tp,
    class R = mp_append<std::tuple<>, remove_cv_ref<Tp>...>>
    R tuple_cat( Tp &&... tp )
{
    std::size_t const N = sizeof...(Tp);

    // inner

    using list1 = mp_list<mp_rename<remove_cv_ref<Tp>, mp_list>...>;

    // ...

最後,是 tuple 類型的類型。到目前為止,我們已經利用了 std::pairstd::tuple 是有效的 Mp11 列表的事實,但是通常,任意 tuple 類型的類型都不是,因此我們需要將它們轉換為這種類型。為此,我們需要定義一個元函式 from_tuple_like,它將採用任意 tuple 類型的類型,並在我們的例子中回傳對應的 mp_list

從技術上講,更合理的做法是回傳 std::tuple,但是這裡 mp_list 會更方便。

我們需要的是,給定一個 tuple 類型的類型 Tp,取得 mp_list<std::tuple_element<0, Tp>::type, std::tuple_element<1, Tp>::type, …​, std::tuple_element<N-1, Tp>::type>,其中 Ntuple_size<Tp>::value。這是一種方法來實現它。

template<class T, class I> using tuple_element =
    typename std::tuple_element<I::value, T>::type;

template<class T> using from_tuple_like =
    mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;

mp_iota<N> 是一種演算法,它回傳一個 mp_list,其中包含元素 mp_size_t<0>mp_size_t<1>、…​、mp_size_t<N-1>。)

請記住,mp_product<F, L1, L2> 會對 L1L2 的元素執行兩個巢狀迴圈,將 F 應用於兩個變數並收集結果。在我們的例子中,L1 由單個元素 T 組成,因此只剩下第二個迴圈(遍歷 mp_iota<N>,其中 Ntuple_size<T>),並且我們獲得一個與 L1 類型相同的列表(一個 mp_list),其內容為 tuple_element<T, mp_size_t<0>>tuple_element<T, mp_size_t<1>>、…​、tuple_element<T, mp_size_t<N-1>>

為了完整起見,這是另一種更傳統的方法來達成相同的結果。

template<class T> using from_tuple_like =
    mp_transform_q<mp_bind_front<tuple_element, T>, mp_iota<std::tuple_size<T>>>;

套用所有這些修復後,我們完全可運作的 tuple_cat 現在看起來像這樣。

template<class L> using F = mp_iota<mp_size<L>>;

template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
    return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
}

template<class T> using remove_cv_ref = typename std::remove_cv<
    typename std::remove_reference<T>::type>::type;

template<class T, class I> using tuple_element =
    typename std::tuple_element<I::value, T>::type;

template<class T> using from_tuple_like =
    mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;

template<class... Tp,
    class R = mp_append<std::tuple<>, from_tuple_like<remove_cv_ref<Tp>>...>>
    R tuple_cat( Tp &&... tp )
{
    std::size_t const N = sizeof...(Tp);

    // inner

    using list1 = mp_list<from_tuple_like<remove_cv_ref<Tp>>...>;
    using list2 = mp_iota_c<N>;

    using list3 = mp_transform<mp_fill, list1, list2>;

    using inner = mp_apply<mp_append, list3>;

    // outer

    using list4 = mp_transform<F, list1>;

    using outer = mp_apply<mp_append, list4>;

    //

    return tuple_cat_<R>( inner(), outer(),
        std::forward_as_tuple( std::forward<Tp>(tp)... ) );
}

計算回傳型別

C++17 有一個稱為 std::variant 的標準變體類型。它還定義了一個函式樣板 std::visit,可用於將函式應用於一個或多個變體的包含值。因此,例如,如果變體 v1 包含 1,而變體 v2 包含 2.0f,則 std::visit(f, v1, v2) 將呼叫 f(1, 2.0f)

但是,std::visit 有一個限制:除非函式的所有可能應用都具有相同的回傳類型,否則它無法回傳結果。例如,如果 v1v2 都是 std::variant<short, int, float> 類型,

std::visit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );

將無法編譯,因為 x + y 的結果可以是 intfloat,取決於 v1v2 所保留的內容。

已經存在一種可以保留 intfloat 的類型,令人驚訝地稱為 std::variant<int, float>。讓我們編寫自己的函式樣板 rvisit,它與 visit 相同,但回傳 variant

template<class F, class... V> auto rvisit( F&& f, V&&... v )
{
    using R = /*...*/;

    return std::visit( [&]( auto&&... x )
        { return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); },
        std::forward<V>( v )... );
}

這基本上是呼叫 std::visit 來完成工作,但是我們傳遞的不是 f,而是一個 lambda 函式,其作用與 f 相同,除了它將結果轉換為共同類型 RR 應該是 std::variant<…​>,其中省略號表示使用所有可能的變體值組合呼叫 f 的回傳類型。

我們首先定義一個輔助的引號元函式 Qret<F>,它會回傳將 F 應用於 T…​ 類型引數的結果。

template<class F> struct Qret
{
    template<class... T> using fn =
        decltype( std::declval<F>()( std::declval<T>()... ) );
};

事實證明,C++17 已經包含一個元函式,它會回傳將函式 F 應用於 T…​ 類型引數的結果:std::invoke_result_t<F, T…​>。我們可以利用它來簡化我們的 Qret

template<class F> struct Qret
{
    template<class... T> using fn = std::invoke_result_t<F, T...>;
};

在 Mp11 中,可以更簡潔地表示為

using Qret = mp_bind_front<std::invoke_result_t, F>;

有了 Qret,可能的傳回類型的 variant 只是將其應用於變體值的可能組合的問題。

using R = mp_product_q<Qret, remove_cv_ref<V>...>;

為什麼會這樣?mp_product<F, L1<T1…​>, L2<T2…​>, …​, Ln<Tn…​>> 會回傳 L1<F<U1, U2, …​, Un>, …​>,其中 Ui 會遍歷列表值的所有可能組合。由於在我們的例子中,所有 Li 都是 std::variant,因此結果也將是 std::variant。(mp_product_qmp_product 相同,但適用於引號元函式,例如我們的 Qret。)

還剩下一個步驟。假設,如上所述,我們傳遞兩個類型為 std::variant<short, int, float> 的變體,而 F[]( auto const& x, auto const& y ){ return x + y; }。這將產生長度為 9 的 R,每個組合一個,但是其中許多元素將相同,不是 int 就是 float,我們需要過濾掉重複項。因此,我們將結果傳遞給 mp_unique

using R = mp_unique<mp_product_q<Qret, remove_cv_ref<V>...>>;

我們就完成了。

#include <boost/mp11.hpp>
#include <boost/core/demangle.hpp>
#include <variant>
#include <type_traits>
#include <typeinfo>
#include <iostream>

using namespace boost::mp11;

template<class T> using remove_cv_ref = typename std::remove_cv<
    typename std::remove_reference<T>::type>::type;

template<class F, class... V> auto rvisit( F&& f, V&&... v )
{
    using Qret = mp_bind_front<std::invoke_result_t, F>;

    using R = mp_unique<mp_product_q<Qret, remove_cv_ref<V>...>>;

    return std::visit( [&]( auto&&... x )
        { return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); },
        std::forward<V>( v )... );
}

template<class T> std::string name()
{
    return boost::core::demangle( typeid(T).name() );
}

template<class V> void print_variant( char const * n, V const& v )
{
    std::cout << "(" << name<decltype(v)>() << ")" << n << ": ";

    std::visit( []( auto const& x )
        { std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v );
}

int main()
{
    std::variant<char, int, float> v1( 1 );

    print_variant( "v1", v1 );

    std::variant<short, int, double> const v2( 3.14 );

    print_variant( "v2", v2 );

    auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );

    print_variant( "v3", v3 );
}

修訂歷史

1.87.0 版的變更

  • 新增 mp_lambda (由 Joaquin M Lopez Munoz 貢獻)

1.85.0 版的變更

  • 新增 mp_sliding_foldmp_pairwise_fold 的泛化 (由 Braden Ganetsky 貢獻)

  • 新增 mp_slice (感謝 Braden Ganetsky)

  • mp_min_elementmp_max_element 新增值列表支援。

  • mp_transform 新增有限的值列表支援。

1.83.0 版的變更

  • mp_from_sequencemp_iotamp_iota_c 新增偏移/起始參數。

  • 新增 mp_valuemp_list_vmp_rename_vmp_is_value_list

  • <boost/mp11/list.hpp> 中的基本類型新增值列表支援。

  • mp_repeatmp_fillmp_atmp_backmp_takemp_pop_backmp_dropmp_insertmp_erase 新增值列表支援。

1.79.0 版的變更

  • 新增 mp_valid_and_true (由 Dmitry Arkhipov 貢獻)

1.78.0 版的變更

  • mp_compose 新增 n 元函式支援 (由 Dmitry Arkhipov 貢獻)

1.77.0 版的變更

  • 新增 mp_interspersemp_splitmp_join

1.75.0 版的變更

  • 新增 mp_pairwise_fold (由 Barry Revzin 建議)

  • 移除 mp_invoke (使用 mp_invoke_q)

1.74.0 版的變更

  • 改善大型 Nmp_with_index<N> 的編譯效能

  • 新增 tuple_transform (由 Hans Dembinski 貢獻)

1.73.0 版的變更

  • 新增 mp_unique_if (由 Kris Jusiak 貢獻)

  • 新增 mp_flatten

  • 新增 mp_rotate_leftmp_rotate_right (由 Duncan Barber 貢獻)

  • 新增 mp_compose

  • 新增 mp_power_set

  • 新增 mp_partial_sum

  • 新增 mp_iterate

1.70.0 版的變更

  • mp_invoke 更名為 mp_invoke_q

  • 新增 mp_similar

  • 新增 mp_set_unionmp_set_intersectionmp_set_difference

  • 新增 mp_not_fn

  • 新增 mp_transform_firstmp_transform_secondmp_transform_third

  • 新增 mp_filter

  • 新增 mp_eval_if_notmp_eval_ormp_valid_q

  • 新增 mp_backmp_pop_back

  • 新增 BOOST_MP11_VERSION

1.69.0 版的變更

  • 移除對 Boost.Config 的依賴;Mp11 現在是獨立的

  • 改進 mp_with_index 的程式碼產生

  • 新增 mp_starts_with (由 Glen Fernandes 貢獻)

  • 新增 CMake 支援

參考

程式庫的內容位於 boost::mp11 命名空間中。

整數常數,<boost/mp11/integral.hpp>

對於 Mp11 整數常數型別 TT::value 在 C++ 的意義上是一個整數常數。

mp_bool<B>

template<bool B> using mp_bool = std::integral_constant<bool, B>;

與 C++17 中的 std::bool_constant 相同。

mp_true

using mp_true = mp_bool<true>;

std::true_type 相同。

mp_false

using mp_false = mp_bool<false>;

std::false_type 相同。

mp_to_bool<T>

template<class T> using mp_to_bool = mp_bool<static_cast<bool>(T::value)>;

mp_not<T>

template<class T> using mp_not = mp_bool< !T::value >;

mp_int<I>

template<int I> using mp_int = std::integral_constant<int, I>;

mp_size_t<N>

template<std::size_t N> using mp_size_t = std::integral_constant<std::size_t, N>;

mp_value<A>

template<auto A> using mp_value = std::integral_constant<decltype(A), A>;

當值列表透過 mp_rename 明確轉換為型別列表,或透過直接支援值列表的原始型別隱式轉換時,其值會透過使用 mp_value 包裝轉換為型別。

需要 C++17。

列表操作,<boost/mp11/list.hpp>

mp_list<T…​>

template<class... T> struct mp_list {};

mp_list 是 Mp11 的標準列表型別,儘管程式庫不限於此,並且可以對任意類別範本進行操作,例如 std::tuplestd::variant。即使轉換不會改變列表中元素的數量,也可以使用 std::pair

mp_list_c<T, I…​>

template<class T, T... I> using mp_list_c =
    mp_list<std::integral_constant<T, I>...>;

mp_list_c 會產生一個 mp_list,其類型對應於其整數範本引數的 std::integral_constant

程式碼範例 1. 使用 mp_list_c
using L1 = mp_list_c<int, 2, 3>; // mp_list<mp_int<2>, mp_int<3>>

mp_list_v<A…​>

template<auto... A> struct mp_list_v {};

Mp11 的標準值列表型別。需要 C++17。

mp_is_list<L>

template<class L> using mp_is_list = /*...*/;

如果 L 是一個列表(一個類別範本的實例化,其範本參數是型別),則 mp_is_list<L>mp_true,否則為 mp_false

mp_is_value_list<L>

template<class L> using mp_is_value_list = /*...*/;

如果 L 是一個值列表(一個類別範本的實例化,其範本參數都是值),則在 C++17 下,mp_is_value_list<L>mp_true,否則為 mp_false

mp_size<L>

template<class L> using mp_size = /*...*/;

mp_size<L>mp_size_t 的形式傳回列表 L 中元素的數量。換句話說,mp_size<L<T…​>>mp_size_t<sizeof…​(T)> 的別名。

在 C++17 下支援值列表作為 L

程式碼範例 2. 將 mp_size 與 mp_list 一起使用
using L1 = mp_list<>;
using R1 = mp_size<L1>; // mp_size_t<0>
程式碼範例 3. 將 mp_size 與 std::pair 一起使用
using L2 = std::pair<int, int>;
using R2 = mp_size<L2>; // mp_size_t<2>
程式碼範例 4. 將 mp_size 與 std::tuple 一起使用
using L3 = std::tuple<float>;
using R3 = mp_size<L3>; // mp_size_t<1>
程式碼範例 5. 將 mp_size 與 mp_list_v 一起使用
using L4 = mp_list_v<1, false, 8ull>;
using R4 = mp_size<L4>; // mp_size_t<3>

mp_empty<L>

template<class L> using mp_empty = mp_bool<mp_size<L>::value == 0>;

如果列表 L 為空,則 mp_empty<L>mp_true 的別名,否則為 mp_false

在 C++17 下支援值列表作為 L

程式碼範例 6. 將 mp_empty 與 std::tuple 一起使用
using L1 = std::tuple<float>;
using R1 = mp_empty<L1>; // mp_false

using L2 = std::tuple<>;
using R2 = mp_empty<L2>; // mp_true

mp_assign<L1, L2>

template<class L1, class L2> using mp_assign = /*...*/;

mp_assign<L1<T1…​>, L2<T2…​>>L1<T2…​> 的別名。也就是說,它會將 L1 的元素替換為 L2 的元素。

在 C++17 下支援值列表作為 L1L2。當將值指派給型別時,會將它們包裝在 mp_value 中。當將型別指派給值時,會使用 T::value 解包它們。

程式碼範例 7. 將 mp_assign 與 mp_list 和 std::tuple 一起使用
using L1 = std::tuple<long>;
using L2 = mp_list<int, float>;

using R1 = mp_assign<L1, L2>; // std::tuple<int, float>
程式碼範例 8. 將 mp_assign 與 mp_list 和 std::pair 一起使用
using L1 = std::pair<long, char>;
using L2 = mp_list<int, float>;

using R1 = mp_assign<L1, L2>; // std::pair<int, float>
程式碼範例 9. 將 mp_assign 與值列表一起使用
using L1 = mp_list<int, float>;
using L2 = mp_list_v<0, false>;

using R1 = mp_assign<L1, L2>; // mp_list<mp_int<0>, mp_false>

mp_clear<L>

template<class L> using mp_clear = mp_assign<L, mp_list<>>;

mp_clear<L<T…​>>L<> 的別名,也就是說,它會移除 L 的元素。

在 C++17 下支援值列表作為 L

程式碼範例 10. 將 mp_clear 與 std::tuple 一起使用
using L1 = std::tuple<int, float>;
using R1 = mp_clear<L1>; // std::tuple<>
程式碼範例 11. 將 mp_clear 與 mp_list_v 一起使用
using L1 = mp_list_v<0, true>;
using R1 = mp_clear<L1>; // mp_list_v<>

mp_front<L>

template<class L> using mp_front = /*...*/;

mp_front<L> 是列表 L 的第一個元素。也就是說,mp_front<L<T1, T…​>>T1 的別名。

在 C++17 下支援值列表作為 L。在這種情況下,傳回的元素會包裝在 mp_value 中。

程式碼範例 12. 將 mp_front 與 std::pair 一起使用
using L1 = std::pair<int, float>;
using R1 = mp_front<L1>; // int
程式碼範例 13. 將 mp_front 與 std::tuple 一起使用
using L2 = std::tuple<float, double, long double>;
using R2 = mp_front<L2>; // float
程式碼範例 14. 將 mp_front 與 mp_list 一起使用
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_front<L3>; // char[1]
程式碼範例 15. 將 mp_front 與 mp_list_v 一起使用
using L4 = mp_list_v<1, 2, 3, 4>;
using R4 = mp_front<L4>; // mp_int<1>

mp_pop_front<L>

template<class L> using mp_pop_front = /*...*/;

mp_pop_front<L> 會移除列表 L 的第一個元素。也就是說,mp_pop_front<L<T1, T…​>>L<T…​> 的別名。

在 C++17 下支援值列表作為 L

程式碼範例 16. 將 mp_pop_front 與 std::tuple 一起使用
using L1 = std::tuple<float, double, long double>;
using R1 = mp_pop_front<L1>; // std::tuple<double, long double>
程式碼範例 17. 將 mp_pop_front 與 mp_list 一起使用
using L2 = mp_list<void>;
using R2 = mp_pop_front<L2>; // mp_list<>
程式碼範例 18. 將 mp_pop_front 與 mp_list_v 一起使用
using L3 = mp_list_v<1, 2, 3, 4>;
using R3 = mp_pop_front<L3>; // mp_list_v<2, 3, 4>

mp_first<L>

template<class L> using mp_first = mp_front<L>;

mp_firstmp_front 的另一個名稱。

mp_rest<L>

template<class L> using mp_rest = mp_pop_front<L>;

mp_restmp_pop_front 的另一個名稱。

mp_second<L>

template<class L> using mp_second = /*...*/;

mp_second<L> 是列表 L 的第二個元素。也就是說,mp_second<L<T1, T2, T…​>>T2 的別名。

在 C++17 下支援值列表作為 L。在這種情況下,傳回的元素會包裝在 mp_value 中。

程式碼範例 19. 將 mp_second 與 std::pair 一起使用
using L1 = std::pair<int, float>;
using R1 = mp_second<L1>; // float
程式碼範例 20. 將 mp_second 與 std::tuple 一起使用
using L2 = std::tuple<float, double, long double>;
using R2 = mp_second<L2>; // double
程式碼範例 21. 將 mp_second 與 mp_list 一起使用
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_second<L3>; // char[2]
程式碼範例 22. 將 mp_second 與 mp_list_v 一起使用
using L4 = mp_list_v<1, 2, 3, 4>;
using R4 = mp_second<L4>; // mp_int<2>

mp_third<L>

template<class L> using mp_third = /*...*/;

mp_third<L> 是列表 L 的第三個元素。也就是說,mp_third<L<T1, T2, T3, T…​>>T3 的別名。

在 C++17 下支援值列表作為 L。在這種情況下,傳回的元素會包裝在 mp_value 中。

程式碼範例 23. 將 mp_third 與 std::tuple 一起使用
using L1 = std::tuple<float, double, long double>;
using R1 = mp_third<L1>; // long double
程式碼範例 24. 將 mp_third 與 mp_list 一起使用
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
using R2 = mp_third<L2>; // char[3]
程式碼範例 25. 將 mp_third 與 mp_list_v 一起使用
using L3 = mp_list<1, 2, 3, 4>;
using R3 = mp_third<L3>; // mp_int<3>

mp_push_front<L, T…​>

template<class L, class... T> using mp_push_front = /*...*/;

mp_push_front<L, T…​> 會將元素 T…​ 插入到列表 L 的開頭。也就是說,mp_push_front<L<U…​>, T…​>L<T…​, U…​> 的別名。

在 C++17 下支援值列表作為 L。在這種情況下,mp_push_front<L<A…​>, T…​>L<T::value…​, A…​>

程式碼範例 26. 將 mp_push_front 與 std::tuple 一起使用
using L1 = std::tuple<double, long double>;
using R1 = mp_push_front<L1, float>; // std::tuple<float, double, long double>
程式碼範例 27. 將 mp_push_front 與 mp_list 一起使用
using L2 = mp_list<void>;
using R2 = mp_push_front<L2, char[1], char[2]>; // mp_list<char[1], char[2], void>
程式碼範例 28. 將 mp_push_front 與 mp_list_v 一起使用
using L3 = mp_list_v<0, 1>;
using R3 = mp_push_front<L3, mp_true, mp_false>; // mp_list_v<true, false, 0, 1>

mp_push_back<L, T…​>

template<class L, class... T> using mp_push_back = /*...*/;

mp_push_back<L, T…​> 會將元素 T…​ 插入到列表 L 的結尾。也就是說,mp_push_back<L<U…​>, T…​>L<U…​, T…​> 的別名。

在 C++17 下支援值列表作為 L。在這種情況下,mp_push_back<L<A…​>, T…​>L<A…​, T::value…​>

程式碼範例 29. 將 mp_push_back 與 std::tuple 一起使用
using L1 = std::tuple<double, long double>;
using R1 = mp_push_back<L1, float>; // std::tuple<double, long double, float>
程式碼範例 30. 將 mp_push_back 與 mp_list 一起使用
using L2 = mp_list<void>;
using R2 = mp_push_back<L2, char[1], char[2]>; // mp_list<void, char[1], char[2]>
程式碼範例 31. 將 mp_push_back 與 mp_list_v 一起使用
using L3 = mp_list_v<0, 1>;
using R3 = mp_push_front<L3, mp_true, mp_false>; // mp_list_v<0, 1, true, false>

mp_rename<L, Y>

template<class L, template<class...> class Y> using mp_rename = /*...*/;

mp_rename<L, Y> 會將列表 L 的類型變更為 Y。也就是說,mp_rename<L<T…​>, Y>Y<T…​> 的別名。

在 C++17 下支援值列表作為 L。在這種情況下,mp_rename<L<A…​>, Y>Y<mp_value<A>…​>

程式碼範例 32. 使用 mp_rename 將 std::pair 更名為 std::tuple
using L1 = std::pair<double, long double>;
using R1 = mp_rename<L1, std::tuple>; // std::tuple<double, long double>
程式碼範例 33. 使用 mp_rename 將 std::tuple 更名為 mp_list
using L2 = std::tuple<void>;
using R2 = mp_rename<L2, mp_list>; // mp_list<void>
程式碼範例 34. 使用 mp_rename 將值列表轉換為型別列表
using L3 = mp_list_v<false, 7>;
using R3 = mp_rename<L3, mp_list>; // mp_list<mp_false, mp_int<7>>

mp_apply<F, L>

template<template<class...> class F, class L> using mp_apply = mp_rename<L, F>;

mp_apply<F, L> 會將中繼函式 F 應用於列表 L 的內容,也就是說,mp_apply<F, L<T…​>>F<T…​> 的別名。(mp_apply 與參數反轉的 mp_rename 相同。)

程式碼範例 35. 將 mp_apply 與 std::pair 一起使用
using L1 = std::pair<double, long double>;
using R1 = mp_apply<std::is_same, L1>; // std::is_same<double, long double>

mp_apply_q<Q, L>

template<class Q, class L> using mp_apply_q = mp_apply<Q::template fn, L>;

mp_apply 相同,但採用引號中繼函式。

程式碼範例 36. 將 mp_apply_q 與 mp_bind_front 一起使用
using L1 = std::tuple<double, long double>;
using L2 = mp_list<int, long>;

using R1 = mp_apply_q<mp_bind_front<mp_push_back, L1>, L2>;
  // R1 is std::tuple<double, long double, int, long>

mp_rename_v<L, Y>

template<class L, template<auto...> class Y> using mp_rename_v = /*...*/;

需要 C++17。

對於值列表 Lmp_rename_v<L<A…​>, Y>Y<A…​>

對於型別列表 Lmp_rename_v<L<T…​>, Y>Y<T::value…​> 的別名。

程式碼範例 37. 使用 mp_rename_v 將型別列表轉換為值列表
using L1 = mp_list<mp_false, mp_int<7>>;
using R1 = mp_rename_v<L1, mp_list_v>; // mp_list_v<false, 7>;

mp_append<L…​>

template<class... L> using mp_append = /*...*/;

mp_append<L…​> 會將 L…​ 中的列表串連為單個列表,該列表與第一個列表具有相同的類型。mp_append<>mp_list<> 的別名。mp_append<L1<T1…​>, L2<T2…​>, …​, Ln<Tn…​>>L1<T1…​, T2…​, …​, Tn…​> 的別名。

在 C++17 下支援值列表,但不支援在同一個 mp_append 中混合型別列表和值列表。

程式碼範例 38. 將 mp_append 與各種型別的列表一起使用
using L1 = std::tuple<double, long double>;
using L2 = mp_list<int>;
using L3 = std::pair<short, long>;
using L4 = mp_list<>;

using R1 = mp_append<L1, L2, L3, L4>;
  // std::tuple<double, long double, int, short, long>
程式碼範例 39. 將 mp_append 與值列表一起使用
using L1 = mp_list_v<true, false>;
using L2 = mp_list_v<0, 1, 2, 3>;

using R1 = mp_append<L1, L2>; // mp_list_v<true, false, 0, 1, 2, 3>

mp_replace_front<L, T>

template<class L, class T> using mp_replace_front = /*...*/;

mp_replace_front<L, T> 會將列表 L 的第一個元素替換為 T。也就是說,mp_replace_front<L<U1, U…​>, T>L<T, U…​> 的別名。

在 C++17 下支援值列表作為 L。在這種情況下,mp_replace_front<L<A1, A…​>, T>L<T::value, A…​>

程式碼範例 40. 將 mp_replace_front 與 std::pair 一起使用
using L1 = std::pair<int, float>;
using R1 = mp_replace_front<L1, void>; // std::pair<void, float>
程式碼範例 41. 將 mp_replace_front 與 std::tuple 一起使用
using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_front<L2, void>; // std::tuple<void, double, long double>
程式碼範例 42. 將 mp_replace_front 與 mp_list 一起使用
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_replace_front<L3, void>; // mp_list<void, char[2], char[3], char[4]>;
程式碼範例 43. 將 mp_replace_front 與 mp_list_v 一起使用
using L4 = mp_list_v<1, 2, 3, 4>;
using R4 = mp_replace_front<L4, mp_false>; // mp_list_v<false, 2, 3, 4>;

mp_replace_first<L, T>

template<class L, class T> using mp_replace_first = mp_replace_front<L, T>;

mp_replace_firstmp_replace_front 的另一個名稱。

mp_replace_second<L, T>

template<class L, class T> using mp_replace_second = /*...*/;

mp_replace_second<L, T> 會將列表 L 的第二個元素替換為 T。也就是說,mp_replace_second<L<U1, U2, U…​>, T>L<U1, T, U…​> 的別名。

在 C++17 下支援值列表作為 L。在這種情況下,mp_replace_second<L<A1, A2, A…​>, T>L<A1, T::value, A…​>

程式碼範例 44. 將 mp_replace_second 與 std::pair 一起使用
using L1 = std::pair<int, float>;
using R1 = mp_replace_second<L1, void>; // std::pair<int, void>
程式碼範例 45. 將 mp_replace_second 與 std::tuple 一起使用
using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_second<L2, void>; // std::tuple<float, void, long double>
程式碼範例 46. 將 mp_replace_second 與 mp_list 一起使用
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_replace_second<L3, void>; // mp_list<char[1], void, char[3], char[4]>;
程式碼範例 47. 將 mp_replace_second 與 mp_list_v 一起使用
using L4 = mp_list_v<1, 2, 3, 4>;
using R4 = mp_replace_second<L4, mp_false>; // mp_list_v<1, false, 3, 4>;

mp_replace_third<L, T>

template<class L, class T> using mp_replace_third = /*...*/;

mp_replace_third<L, T> 會將列表 L 的第三個元素替換為 T。也就是說,mp_replace_third<L<U1, U2, U3, U…​>, T>L<U1, U2, T, U…​> 的別名。

在 C++17 下支援值列表作為 L。在這種情況下,mp_replace_third<L<A1, A2, A3, A…​>, T>L<A1, A2, T::value, A…​>

程式碼範例 48. 將 mp_replace_third 與 std::tuple 一起使用
using L1 = std::tuple<float, double, long double>;
using R1 = mp_replace_third<L1, void>; // std::tuple<float, double, void>
程式碼範例 49. 將 mp_replace_third 與 mp_list 一起使用
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
using R2 = mp_replace_third<L2, void>; // mp_list<char[1], char[2], void, char[4]>;
程式碼範例 50. 將 mp_replace_third 與 mp_list_v 一起使用
using L4 = mp_list_v<1, 2, 3, 4>;
using R4 = mp_replace_third<L4, mp_false>; // mp_list_v<1, 2, false, 4>;

mp_transform_front<L, F>

template<class L, template<class...> class F> using mp_transform_front =
    /*...*/;

mp_transform_front<L, F> 會將列表 L 的第一個元素 T1 替換為 F<T1>

在 C++17 下支援值列表作為 L。在這種情況下,替換為 F<mp_value<T1>>::value

mp_transform_front_q<L, Q>

template<class L, class Q> using mp_transform_front_q =
    mp_transform_front<L, Q::template fn>;

mp_transform_front 相同,但採用引號中繼函式。

mp_transform_first<L, F>

template<class L, template<class...> class F> using mp_transform_first =
    mp_transform_front<L, F>;

mp_transform_firstmp_transform_front 的另一個名稱。

mp_transform_first_q<L, Q>

template<class L, class Q> using mp_transform_first_q =
    mp_transform_first<L, Q::template fn>;

mp_transform_first 相同,但採用引號中繼函式。

mp_transform_second<L, F>

template<class L, template<class...> class F> using mp_transform_second =
    /*...*/;

mp_transform_second<L, F> 會將列表 L 的第二個元素 T2 替換為 F<T2>

在 C++17 下支援值列表作為 L。在這種情況下,替換為 F<mp_value<T2>>::value

mp_transform_second_q<L, Q>

template<class L, class Q> using mp_transform_second_q =
    mp_transform_second<L, Q::template fn>;

mp_transform_second 相同,但採用引號中繼函式。

mp_transform_third<L, F>

template<class L, template<class...> class F> using mp_transform_third =
    /*...*/;

mp_transform_third<L, F> 會將列表 L 的第三個元素 T3 替換為 F<T3>

在 C++17 下支援值列表作為 L。在這種情況下,替換為 F<mp_value<T3>>::value

mp_transform_third_q<L, Q>

template<class L, class Q> using mp_transform_third_q =
    mp_transform_third<L, Q::template fn>;

mp_transform_third 相同,但採用引號中繼函式。

工具元件,<boost/mp11/utility.hpp>

mp_identity<T>

template<class T> struct mp_identity
{
    using type = T;
};

mp_identity 是一個簡單的轉換型別特性(如同 C++ 標準所述),它只會回傳相同的型別。它本身就很有用,也可用作將型別作為值傳遞給函式的型別包裝器。

程式碼範例 51. 將 mp_identity 作為型別特性使用
template<class T> using addp_if_not_ref =
    typename mp_if<std::is_reference<T>, mp_identity<T>, std::add_pointer<T>>::type;
程式碼範例 52. 使用 mp_identity 來保護限定詞和參考
template<class T> void print1()
{
    std::cout << typeid(T).name() << std::endl;
}

template<class T> void print2()
{
    std::cout << typeid(mp_identity<T>).name() << std::endl;
}

int main()
{
    print1<int const&>(); // 'int'
    print2<int const&>(); // 'mp_identity<int const &>'
}

mp_identity_t<T>

template<class T> using mp_identity_t = typename mp_identity<T>::type;

mp_inherit<T…​>

template<class... T> struct mp_inherit: T... {};

mp_if_c<C, T, E…​>

template<bool C, class T, class... E> using mp_if_c = /*...*/;

mp_if_c<true, T, E…​>T 的別名。mp_if_c<false, T, E>E 的別名。否則,結果會是替換失敗。

程式碼範例 53. 使用 mp_if_c 在兩種替代方案之間選擇
using R1 = mp_if_c<true, int, void>;  // int

using R2 = mp_if_c<false, int, void>; // void
程式碼範例 54. 使用 mp_if_c 在條件不符合時導致替換失敗
template<class I> using void_if_5 = mp_if_c<I::value == 5, void>;

I::value 為 5 時,此範例會回傳 void,否則會產生替換失敗。這與 C++14 中的 std::enable_if_t<I::value == 5> 或 C++11 中的 typename std::enable_if<I::value == 5>::type 相同。

mp_if<C, T, E…​>

template<class C, class T, class... E> using mp_if =
    mp_if_c<static_cast<bool>(C::value), T, E...>;

mp_if_c 類似,但第一個引數是型別。

程式碼範例 55. 使用 mp_if 在兩種替代方案之間選擇
using R1 = mp_if<mp_true, int, void>;  // int

using R2 = mp_if<mp_false, int, void>; // void
程式碼範例 56. 使用 mp_if 在條件不符合時導致替換失敗
template<class T> using void_if_const = mp_if<std::is_const<T>, void>;

template<class... T> using void_if_all_const =
    mp_if<mp_all<std::is_const<T>...>, void>;

template<class T> using if_non_const = mp_if<mp_not<std::is_const<T>>, T>;

mp_eval_if_c<C, T, F, U…​>

template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c =
    /*...*/;

Ctrue 時,mp_eval_if_c<C, T, F, U…​>T 的別名,否則為 F<U…​>。其目的是避免在條件為 true 時評估 F<U…​>,因為在這種情況下它可能無效。

程式碼範例 57. 使用 mp_eval_if_c 選擇第一個封包元素,或 void
template<class... T> using first_or_void =
    mp_eval_if_c<sizeof...(T) == 0, void, mp_first, mp_list<T...>>;

mp_eval_if<C, T, F, U…​>

template<class C, class T, template<class...> class F, class... U> using mp_eval_if =
    mp_eval_if_c<static_cast<bool>(C::value), T, F, U...>;

mp_eval_if_c 類似,但第一個引數是型別。

程式碼範例 58. 使用 mp_eval_if 選擇第一個清單元素,或 void
template<class L> using first_or_void = mp_eval_if<mp_empty<L>, void, mp_first, L>;

mp_eval_if_q<C, T, Q, U…​>

template<class C, class T, class Q, class... U> using mp_eval_if_q =
    mp_eval_if<C, T, Q::template fn, U...>;

mp_eval_if 類似,但接受引號中繼函式。

mp_eval_if_not<C, T, F, U…​>

template<class C, class T, template<class...> class F, class... U>
    using mp_eval_if_not = mp_eval_if<mp_not<C>, T, F, U...>;

mp_eval_if 相同,但條件相反。

mp_eval_if_not_q<C, T, Q, U…​>

template<class C, class T, class Q, class... U> using mp_eval_if_not_q =
    mp_eval_if_not<C, T, Q::template fn, U...>;

mp_eval_if_not 相同,但接受引號中繼函式。

mp_valid<F, T…​>

template<template<class...> class F, class... T> using mp_valid = /*...*/;

F<T…​> 是有效表示式時,mp_valid<F, T…​>mp_true 的別名,否則為 mp_false

程式碼範例 59. 使用 mp_valid 編寫一個檢查巢狀型別是否存在的中繼函式
template<class T> using get_nested_type = typename T::type;

template<class T> struct has_nested_type: mp_valid<get_nested_type, T> {};

mp_valid_q<Q, T…​>

template<class Q, class... T> using mp_valid_q = mp_valid<Q::template fn, T...>;

mp_valid 類似,但接受引號中繼函式。

mp_eval_or<T, F, U…​>

template<class T, template<class...> class F, class... U> using mp_eval_or =
    mp_eval_if_not<mp_valid<F, U...>, T, F, U...>;

F<U…​> 這個表示式有效時,mp_eval_or<T, F, U…​>F<U…​> 的別名,否則為 T

程式碼範例 60. 使用 mp_eval_or 選擇第一個封包元素,或 void
template<class... T> using first_or_void =
    mp_eval_or<void, mp_first, mp_list<T...>>;

mp_eval_or_q<T, Q, U…​>

template<class T, class Q, class... U> using mp_eval_or_q =
    mp_eval_or<T, Q::template fn, U...>;

mp_eval_or 類似,但接受引號中繼函式。

mp_valid_and_true<F, T…​>

template<template<class...> class F, class... T> using mp_valid_and_true =
    mp_eval_or<mp_false, F, T...>;

F<T…​> 這個表示式有效時,mp_valid_and_true<F, T…​>F<T…​> 的別名,否則為 mp_false

mp_valid_and_true_q<Q, T…​>

template<class Q, class... T> using mp_valid_and_true_q =
    mp_valid_and_true<Q::template fn, T...>;

mp_valid_and_true 類似,但接受引號中繼函式。

mp_cond<C, T, R…​>

template<class C, class T, class... R> using mp_cond = /*...*/;

static_cast<bool>(C::value)true 時,mp_cond<C, T, R…​>T 的別名。當 static_cast<bool>(C::value)false 時,它是 mp_cond<R…​> 的別名。

(如果 static_cast<bool>(C::value) 是替換失敗,則結果也會是替換失敗。)

程式碼範例 61. 使用 mp_cond
template<int N> using unsigned_ = mp_cond<
    mp_bool<N ==  8>, uint8_t,
    mp_bool<N == 16>, uint16_t,
    mp_bool<N == 32>, uint32_t,
    mp_bool<N == 64>, uint64_t,
    mp_true, unsigned // default case
>;

mp_defer<F, T…​>

template<template<class...> class F, class... T> using mp_defer = /*...*/;

mp_valid<F, T…​>mp_true 時,mp_defer<F, T…​> 是一個具有巢狀型別 type 的結構,它是 F<T…​> 的別名。否則,mp_defer<F, T…​> 是一個空的結構。

mp_quote<F>

template<template<class...> class F> struct mp_quote
{
    template<class... T> using fn = F<T...>;
};

mp_quote<F> 會將樣板 F 轉換為引號中繼函式,這是一種具有巢狀樣板 fn 的型別,使得 fn<T…​> 回傳 F<T…​>

程式碼範例 62. 使用 mp_quote 建立中繼函式清單
using LQ = mp_list<mp_quote<std::is_const>, mp_quote<std::is_volatile>>;

mp_quote_trait<F>

template<template<class...> class F> struct mp_quote_trait
{
    template<class... T> using fn = typename F<T...>::type;
};

mp_quote_trait<F> 會將 C++03 樣式的特性 F 轉換為引號中繼函式。

程式碼範例 63. 將 mp_quote_trait 與 std::add_pointer 搭配使用
using L1 = mp_list<int, void, float>;
using R1 = mp_transform_q<mp_quote_trait<std::add_pointer>, L1>;
  // mp_list<int*, void*, float*>

mp_invoke_q<Q, T…​>

template<class Q, class... T> using mp_invoke_q = typename Q::template fn<T...>;

mp_invoke_q<Q, T…​> 會評估引號中繼函式的巢狀樣板 fnmp_invoke_q<mp_quote<F>, T…​> 會回傳 F<T…​>

程式碼範例 64. 使用 mp_invoke_q 來呼叫中繼函式清單,方法 1
using LQ = mp_list<mp_quote<std::is_const>, mp_quote<std::is_volatile>>;

template<class T> using is_const_and_volatile =
    mp_apply<mp_all, mp_product<mp_invoke_q, LQ, mp_list<T>>>;
程式碼範例 65. 使用 mp_invoke_q 來呼叫中繼函式清單,方法 2
template<class T> using is_const_and_volatile =
    mp_apply<mp_all, mp_transform_q<mp_bind_back<mp_invoke_q, T>, LQ>>;
程式碼範例 66. 使用 mp_invoke_q 來呼叫中繼函式清單,方法 3
template<class T> using is_const_and_volatile =
    mp_apply<mp_all, mp_transform<mp_invoke_q, LQ, mp_fill<LQ, T>>>;

mp_not_fn<P>

template<template<class...> class P> struct mp_not_fn
{
    template<class... T> using fn = mp_not<P<T...>>;
};

mp_not_fn<P> 會回傳一個引號中繼函式 Q,使得 Q::fn<T…​> 回傳 mp_not<P<T…​>>

也就是說,它會否定 P 的結果。

mp_not_fn_q<Q>

template<class Q> using mp_not_fn_q = mp_not_fn<Q::template fn>;

如同 mp_not_fn,但接受引號中繼函式。

mp_compose<F…​>

template<template<class...> class... F> struct mp_compose;

mp_compose<F1, F2, …​, Fn> 是一個引號中繼函式,它會依序將 F1F2、…​、Fn 套用至其引數。也就是說,mp_compose<F1, F2, …​, Fn>::fn<T…​>Fn<…​F2<F1<T…​>>…​>

mp_compose_q<Q…​>

template<class... Q> struct mp_compose_q;

如同 mp_compose,但接受引號中繼函式。

演算法,<boost/mp11/algorithm.hpp>

mp_transform<F, L…​>

template<template<class...> class F, class... L> using mp_transform = /*...*/;

mp_transform<F, L1<T1…​>, L2<T2…​>, …​, Ln<Tn…​>> 會將 F 套用至每個連續的元素元組,並回傳 L1<F<T1, T2, …​, Tn>…​>

在 C++17 下,對值清單作為 L…​ 的支援有限(適用於一到三個清單)。在這種情況下,元素會在傳遞至 F 之前使用 mp_value 包裝,之後再解包。結果為 L1<F<mp_value<T1>, mp_value<T2>, …​>::value…​>

程式碼範例 67. 使用 mp_transform 從指標目標清單產生指標清單
template<class T> using add_pointer_t =
    typename std::add_pointer<T>::type;  // std::add_pointer_t in C++14

using L1 = std::tuple<void, int, float>;
using R1 = mp_transform<add_pointer_t, L1>; // std::tuple<void*, int*, float*>
程式碼範例 68. 使用 mp_transform 比較兩個型別清單的內容
using L1 = std::tuple<void, int, float>;
using L2 = mp_list<void, int, float>;

using R1 = mp_apply<mp_all, mp_transform<std::is_same, L1, L2>>; // mp_true
程式碼範例 69. 使用 mp_transform 比較兩個整數常數清單的內容
template<class T1, class T2> using eq = mp_bool<T1::value == T2::value>;

using L1 = std::tuple<mp_int<1>, mp_int<2>, mp_int<3>>;
using L2 = mp_list<mp_size_t<1>, mp_size_t<2>, mp_size_t<3>>;

using R1 = mp_apply<mp_all, mp_transform<eq, L1, L2>>; // mp_true
圖例 1. 單一清單上的 mp_transform

L1

A1

A2

…​

An

mp_transform<F, L1>

F<A1>

F<A2>

…​

F<An>

圖例 2. 兩個清單上的 mp_transform

L1

A1

A2

…​

An

L2

B1

B2

…​

Bn

mp_transform<F, L1, L2>

F<A1,B1>

F<A2,B2>

…​

F<An,Bn>

mp_transform_q<Q, L…​>

template<class Q, class... L> using mp_transform_q =
    mp_transform<Q::template fn, L...>;

如同 mp_transform,但接受引號中繼函式。

程式碼範例 70. 使用 mp_transform_q 計算清單中 void 的出現次數
using L1 = std::tuple<void, int, float, void, int>;

using R1 = mp_apply<mp_plus,
    mp_transform_q<mp_bind_front<std::is_same, void>, L1>>; // mp_int<2>
圖例 3. 兩個清單上的 mp_transform_q

L1

A1

A2

…​

An

L2

B1

B2

…​

Bn

mp_transform_q<Q, L1, L2>

Q::fn<A1,B1>

Q::fn<A2,B2>

…​

Q::fn<An,Bn>

mp_transform_if<P, F, L…​>

template<template<class...> class P, template<class...> class F, class... L>
    using mp_transform_if = /*...*/;

mp_transform_if<P, F, L1, L2, …​, Ln> 會將 mp_to_bool<P<T1, T2, …​, Tn>>mp_true 的清單 L1 元素取代為 F<T1, T2, …​, Tn>,並回傳結果,其中 TiLi 的對應元素。

程式碼範例 71. 使用 mp_transform_if 將清單中 'void' 的出現次數取代為第二個清單的對應元素
using L1 = std::tuple<void, int, float, void, int>;
using L2 = std::tuple<char[1], char[2], char[3], char[4], char[5]>;

template<class T1, class T2> using first_is_void = std::is_same<T1, void>;
template<class T1, class T2> using second = T2;

using R1 = mp_transform_if<first_is_void, second, L1, L2>;
  // std::tuple<char[1], int, float, char[4], int>
圖例 4. mp_transform_if

L1

A1

A2

…​

An

L2

B1

B2

…​

Bn

P<Ai, Bi>

mp_false

mp_true

…​

mp_false

mp_transform_if<P, F, L1, L2>

A1

F<A2,B2>

…​

An

mp_transform_if_q<Qp, Qf, L…​>

template<class Qp, class Qf, class... L> using mp_transform_if_q =
    mp_transform_if<Qp::template fn, Qf::template fn, L...>;

如同 mp_transform_if,但接受引號中繼函式。

程式碼範例 72. 使用 mp_transform_if_q 將清單中 'void' 的出現次數取代為第二個清單的對應元素
using L1 = std::tuple<void, int, float, void, int>;
using L2 = std::tuple<char[1], char[2], char[3], char[4], char[5]>;

using R1 = mp_transform_if_q<mp_bind<std::is_same, _1, void>, _2, L1, L2>;
  // std::tuple<char[1], int, float, char[4], int>
圖例 5. mp_transform_if_q

L1

A1

A2

…​

An

L2

B1

B2

…​

Bn

Qp::fn<Ai, Bi>

mp_false

mp_true

…​

mp_false

mp_transform_if_q<Qp, _2, L1, L2>

A1

B2

…​

An

mp_filter<P, L…​>

template<template<class...> class P, class... L> using mp_filter = /*...*/;

mp_filter<P, L1, L2, …​, Ln> 會移除 mp_to_bool<P<T1, T2, …​, Tn>>mp_false 的清單 L1 元素,並回傳結果,其中 TiLi 的對應元素。

另請參閱 mp_copy_ifmp_remove_if,它們是 mp_filter 的較不通用的變體,只接受單一清單。

mp_filter_q<Qp, L…​>

template<class Qp, class... L> using mp_filter_q =
    mp_filter<Qp::template fn, L...>;

如同 mp_filter,但接受引號中繼函式。

程式碼範例 73. 使用 mp_filter_q 根據另一個清單中的遮罩來挑選清單的元素
using L1 = std::tuple<void, int, float>;
using L2 = mp_list<mp_true, mp_false, mp_true>;
using R1 = mp_filter_q<_2, L1, L2>; // std::tuple<void, float>

mp_fill<L, V>

template<class L, class V> using mp_fill = /*...*/;

mp_fill<L<T…​>, V> 會回傳 L<V, V, …​, V>,其結果與輸入的大小相同。

在 C++17 下,支援值清單作為 L。在這種情況下,元素會被 V::value 取代。

程式碼範例 74. 將 mp_fill 與 std::tuple 搭配使用
using L1 = std::tuple<void, int, float>;
using R1 = mp_fill<L1, double>; // std::tuple<double, double, double>
程式碼範例 75. 將 mp_fill 與 std::pair 搭配使用
using L1 = std::pair<int, float>;
using R1 = mp_fill<L1, void>; // std::pair<void, void>
程式碼範例 76. 將 mp_fill 與 mp_list_v 搭配使用
using L1 = mp_list_v<true, false>;
using R1 = mp_fill<L1, mp_int<7>>; // mp_list_v<7, 7>
圖例 6. mp_fill

L1

A1

A2

…​

An

mp_fill<L1, V>

V

V

…​

V

mp_count<L, V>

template<class L, class V> using mp_count = /*...*/;

mp_count<L, V> 會回傳 mp_size_t<N>,其中 N 是與 V 相同的 L 元素數目。

mp_count_if<L, P>

template<class L, template<class...> class P> using mp_count_if = /*...*/;

mp_count_if<L, P> 會回傳 mp_size_t<N>,其中 Nmp_to_bool<P<T>>mp_trueL 元素 T 數目。

mp_count_if_q<L, Q>

template<class L, class Q> using mp_count_if_q = mp_count_if<L, Q::template fn>;

如同 mp_count_if,但接受引號中繼函式。

mp_contains<L, V>

template<class L, class V> using mp_contains = mp_to_bool<mp_count<L, V>>;

L 包含元素 V 時,mp_contains<L, V>mp_true,否則為 mp_false

mp_starts_with<L1, L2>

template<class L1, class L2> using mp_starts_with = /*...*/;

L1L2 開頭時,mp_starts_with<L1, L2>mp_true,否則為 mp_false

mp_repeat_c<L, N>

template<class L, std::size_t N> using mp_repeat_c = /*...*/;

mp_repeat_c<L, N> 會回傳與 L 相同形式的清單,其中包含 LN 個串連複本。

在 C++17 下支援值列表作為 L

程式碼範例 77. 使用 mp_repeat_c
using L1 = tuple<int>;
using R1 = mp_repeat_c<L1, 3>; // tuple<int, int, int>

using L2 = pair<int, float>;
using R2 = mp_repeat_c<L2, 1>; // pair<int, float>

using L3 = mp_list<int, float>;
using R3 = mp_repeat_c<L3, 2>; // mp_list<int, float, int, float>

using L4 = mp_list<int, float, double>;
using R4 = mp_repeat_c<L4, 0>; // mp_list<>

using L5 = mp_list_v<true, 8>;
using R5 = mp_repeat_c<L5, 2>; // mp_list_v<true, 8, true, 8>

mp_repeat<L, N>

template<class L, class N> using mp_repeat = /*...*/;

mp_repeat_c 相同,但具有型別引數 N。複本數目為 N::value,且必須為非負數。

在 C++17 下支援值列表作為 L

mp_product<F, L…​>

template<template<class...> class F, class... L> using mp_product = /*...*/;

mp_product<F, L1<T1…​>, L2<T2…​>, …​, Ln<Tn…​>> 會針對從清單的笛卡爾乘積中取的值 Ui 來評估 F<U1, U2, …​, Un>,就像元素 Ui 是由 n 個巢狀迴圈形成的,每個迴圈都會遍歷 Li 一樣。它會回傳一個 L1<V…​> 形式的清單,其中包含 F 應用程式的結果。零清單的簡化情況 mp_product<F> 會回傳 mp_list<F<>>

圖例 7. 兩個清單上的 mp_product

L1

A1

A2

…​

An

L2

B1

B2

…​

Bm

mp_product<F, L1, L2>

F<A1,B1>

F<A1,B2>

…​

F<A1,Bm>

F<A2,B1>

F<A2,B2>

…​

F<A2,Bm>

…​

F<An,B1>

F<An,B2>

…​

F<An,Bm>

mp_product_q<Q, L…​>

template<class Q, class... L> using mp_product_q = mp_product<Q::template fn, L...>;

如同 mp_product,但接受引號中繼函式。

mp_power_set<L>

template<class L> using mp_power_set = /*...*/;

mp_power_set<L> 會回傳 L 的所有可能 2n 個子集合的清單(與 L 的形式相同)(其中 nL 的長度)。

mp_power_set<L<>> 會回傳 L<L<>>

mp_power_set<L<T1>> 會回傳 L<L<>, L<T1>>

mp_power_set<L<T1, T2>> 會回傳 L<L<>, L<T2>, L<T1>, L<T1, T2>>

mp_power_set<L<T1, T…​>> 會回傳 mp_power_set<L<T…​>> 的串連,以及在每個元素前加上 T1 的相同清單。

mp_drop_c<L, N>

template<class L, std::size_t N> using mp_drop_c = /*...*/;

mp_drop_c<L, N> 會移除 L 的前 N 個元素,並回傳結果。

在 C++17 下,支援值清單作為 L

圖例 8. mp_drop_c

L1

A1

…​

Am

Am+1

…​

An

mp_drop_c<L1, M>

Am+1

…​

An

mp_drop<L, N>

template<class L, class N> using mp_drop = /*...*/;

mp_drop_c 相同,但具有型別引數 NN::value 必須是非負數。

mp_from_sequence<S, F>

template<class S, class F = mp_int<0>> using mp_from_sequence = /*...*/

mp_from_sequence 會將 make_integer_sequence 產生的整數序列轉換為對應的 std::integral_constant 型別的 mp_list。如果提供選用的第二個參數 F,則會將 F::value 的偏移量新增至所有值。

給定

template<class T, T... I> struct S;

mp_from_sequence<S<T, I…​>, F>mp_list<std::integral_constant<T, I + F::value>…​> 的別名。

mp_iota_c<N, F>

template<std::size_t N, std::size_t F = 0> using mp_iota_c = /*...*/;

mp_iota_c<N, F>mp_list<mp_size_t<F+0>, mp_size_t<F+1>, …​, mp_size_t<F+N-1>> 的別名。

範例 9. mp_iota_c

mp_iota_c<4>

mp_size_t<0>

mp_size_t<1>

mp_size_t<2>

mp_size_t<3>

mp_iota_c<4, 2>

mp_size_t<2>

mp_size_t<3>

mp_size_t<4>

mp_size_t<5>

mp_iota<N, F>

template<class N, class F = mp_int<0>> using mp_iota = /*...*/;

mp_iota_c 相同,但使用型別參數 NFN::value 必須是非負數。回傳 mp_list<std::integral_constant<T, F::value+0>, std::integral_constant<T, F::value+1>, …​, std::integral_constant<T, F::value+N::value-1>>,其中 TN::value 的型別。

範例 10. mp_iota

mp_iota<mp_size_t<4>>

mp_size_t<0>

mp_size_t<1>

mp_size_t<2>

mp_size_t<3>

mp_iota<mp_int<4>, mp_int<-2>>

mp_int<-2>

mp_int<-1>

mp_int<0>

mp_int<+1>

mp_at_c<L, I>

template<class L, std::size_t I> using mp_at_c = /*...*/;

mp_at_c<L, I> 回傳 L 的第 I 個元素,索引從零開始。

在 C++17 中,支援將數值列表作為 L。在這種情況下,回傳的元素會使用 mp_value 包裝。

mp_at<L, I>

template<class L, class I> using mp_at = /*...*/;

mp_at_c 相同,但使用型別參數 II::value 必須是非負數。

mp_take_c<L, N>

template<class L, std::size_t N> using mp_take_c = /*...*/;

mp_take_c<L, N> 回傳一個與 L 相同形式的列表,其中包含 L 的前 N 個元素。

在 C++17 下,支援值清單作為 L

範例 11. mp_take_c

L1

A1

…​

Am

Am+1

…​

An

mp_take_c<L1, M>

A1

…​

Am

mp_take<L, N>

template<class L, class N> using mp_take = /*...*/;

mp_take_c 相同,但使用型別參數 NN::value 必須是非負數。

mp_slice_c<L, I, J>

template<class L, std::size_t I, std::size_t J> using mp_slice_c = mp_drop_c<mp_take_c<L, J>, I>;

mp_slice_c<L, I, J> 回傳一個與 L 相同形式的列表,其中包含索引從 I (包含) 到 J (不包含) 的元素。

在 C++17 下,支援值清單作為 L

範例 12. mp_slice_c

L1

A0

…​

Ai

…​

Aj-1

Aj

…​

An-1

mp_slice_c<L1, I, J>

Ai

…​

Aj-1

mp_slice<L, I, J>

template<class L, class I, class J> using mp_slice = mp_drop<mp_take<L, J>, I>;

mp_slice_c 相同,但使用型別參數 IJI::valueJ::value 必須是非負數。

mp_back<L>

template<class L> using mp_back = mp_at_c<L, mp_size<L>::value - 1>;

mp_back<L> 回傳列表 L 的最後一個元素。

在 C++17 中,支援將數值列表作為 L。在這種情況下,回傳的元素會使用 mp_value 包裝。

mp_pop_back<L>

template<class L> using mp_pop_back = mp_take_c<L, mp_size<L>::value - 1>;

mp_pop_back<L> 移除列表 L 的最後一個元素並回傳結果。

在 C++17 下,支援值清單作為 L

mp_insert_c<L, I, T…​>

template<class L, std::size_t I, class... T> using mp_insert_c =
    mp_append<mp_take_c<L, I>, mp_push_front<mp_drop_c<L, I>, T...>>;

將元素 T…​ 插入到列表 L 的位置 I (索引從零開始)。

在 C++17 中,支援將數值列表作為 L。在這種情況下,會插入元素 T::value…​

範例 13. 使用兩個元素的 mp_insert_c

L1

A1

…​

Am

Am+1

…​

An

mp_insert_c<L1, M, B1, B2>

A1

…​

Am

B1

B2

Am+1

…​

An

mp_insert<L, I, T…​>

template<class L, class I, class... T> using mp_insert =
    mp_append<mp_take<L, I>, mp_push_front<mp_drop<L, I>, T...>>;

mp_insert_c 相同,但使用型別參數 I

mp_erase_c<L, I, J>

template<class L, std::size_t I, std::size_t J> using mp_erase_c =
    mp_append<mp_take_c<L, I>, mp_drop_c<L, J>>;

從列表 L 中移除索引從 I (包含) 到 J (不包含) 的元素。

在 C++17 下,支援值清單作為 L

範例 14. mp_erase_c

L1

A0

…​

Ai-1

Ai

…​

Aj-1

Aj

…​

An-1

mp_erase_c<L1, I, J>

A0

…​

Ai-1

Aj

…​

An-1

mp_erase<L, I, J>

template<class L, class I, class J> using mp_erase =
    mp_append<mp_take<L, I>, mp_drop<L, J>>;

mp_erase_c 相同,但使用型別參數 IJ

mp_replace<L, V, W>

template<class L, class V, class W> using mp_replace = /*...*/;

L 中所有 V 元素替換為 W 並回傳結果。

範例 15. mp_replace

L1

A1

V

…​

An

mp_replace<L1, V, W>

A1

W

…​

An

mp_replace_if<L, P, W>

template<class L, template<class...> class P, class W> using mp_replace_if = /*...*/;

L 中所有滿足 mp_to_bool<P<T>>mp_trueT 元素替換為 W 並回傳結果。

範例 16. mp_replace_if

L1

A1

A2

…​

An

P<Ai>

mp_false

mp_true

…​

mp_false

mp_replace_if<L1, P, W>

A1

W

…​

An

mp_replace_if_q<L, Q, W>

template<class L, class Q, class W> using mp_replace_if_q =
    mp_replace_if<L, Q::template fn, W>;

mp_replace_if 相同,但使用引用的元函數。

mp_replace_at_c<L, I, W>

template<class L, std::size_t I, class W> using mp_replace_at_c = /*...*/;

L 中索引為零的第 I 個元素替換為 W 並回傳結果。

mp_replace_at<L, I, W>

template<class L, class I, class W> using mp_replace_at = /*...*/;

mp_replace_at_c 相同,但使用型別參數 II::value 必須是非負數。

mp_rotate_left_c<L, N>

template<class L, std::size_t N> using mp_rotate_left_c = /*...*/;

將列表 L 的前 N % M 個元素移動到尾端,其中 ML 的大小。空的列表保持不變。

mp_rotate_left<L, N>

template<class L, class N> using mp_rotate_left = /*...*/;

mp_rotate_left_c 相同,但使用型別參數 NN::value 必須是非負數。

mp_rotate_right_c<L, N>

template<class L, std::size_t N> using mp_rotate_right_c = /*...*/;

將列表 L 的後 N % M 個元素移動到前端,其中 ML 的大小。空的列表保持不變。

mp_rotate_right<L, N>

template<class L, class N> using mp_rotate_right = /*...*/;

mp_rotate_right_c 相同,但使用型別參數 NN::value 必須是非負數。

mp_copy_if<L, P>

template<class L, template<class...> class P> using mp_copy_if = /*...*/;

L 中滿足 mp_to_bool<P<T>>mp_true 的元素 T 複製到一個相同形式的新列表中並回傳。

mp_copy_if_q<L, Q>

template<class L, class Q> using mp_copy_if_q = mp_copy_if<L, Q::template fn>;

mp_copy_if 相同,但使用引用的元函數。

mp_remove<L, V>

template<class L, class V> using mp_remove = /*...*/;

移除 L 中所有 V 元素並回傳結果。

mp_remove_if<L, P>

template<class L, template<class...> class P> using mp_remove_if = /*...*/;

移除 L 中所有滿足 mp_to_bool<P<T>>mp_true 的元素 T 並回傳結果。

mp_remove_if_q<L, Q>

template<class L, class Q> using mp_remove_if_q = mp_remove_if<L, Q::template fn>;

mp_remove_if 相同,但使用引用的元函數。

mp_flatten<L>

template<class L, class L2 = mp_clear<L>> using mp_flatten = /*...*/;

L 中所有與 L2 形式相同的列表元素 T (也就是說,滿足 mp_similar<T, L2>mp_true 的元素) 替換為它們的元素並回傳結果。

程式碼範例 78. 使用 mp_flatten
using L1 = tuple<int, tuple<>, void, tuple<float, double>>;
using R1 = mp_flatten<L1>; // tuple<int, void, float, double>

using L2 = mp_list<int, mp_list<float>, tuple<void>>;
using R2a = mp_flatten<L2>; // mp_list<int, float, tuple<void>>
using R2b = mp_flatten<L2, tuple<>>; // mp_list<int, mp_list<float>, void>

using L3 = mp_list<mp_list<float>, mp_list<mp_list<void>>>;
using R3 = mp_flatten<L3>; // mp_list<float, mp_list<void>>

mp_intersperse<L, S>

template<class L, class S> using mp_intersperse = /*...*/;

在列表 L 的元素之間插入分隔符號 S

mp_intersperse<L<>, S>L<>mp_intersperse<L<T1>, S>L<T1>mp_intersperse<L<T1, T2, T3, …​, Tn-1, Tn>, S>L<T1, S, T2, S, T3, S, …​, Tn-1, S, Tn>

mp_split<L, S>

template<class L, class S> using mp_split = /*...*/;

將列表 L 在每個分隔符號 S 的位置分割成區段,並回傳區段列表。

mp_split<L<>, S>L<L<>>。如果 S 沒有出現在 T…​ 中,則 mp_split<L<T…​>, S>L<L<T…​>>mp_split<L<T1…​, S, T2…​, S, T3…​>, S>L<L<T1…​>, L<T2…​>, L<T3…​>>

區段可能為空;mp_split<L<S, X, Y, S, S>, S>L<L<>, L<X, Y>, L<>, L<>>

mp_join<L, S>

template<class L, class S> using mp_join = /*...*/;

mp_joinmp_split 的反向操作;它接受區段列表 L 並將它們合併成一個列表,並在它們之間插入分隔符號 S

mp_join<mp_split<L, S>, S> 會還原為原始列表 L

例如,mp_split<L<X1, X2, S, X3>, S> 會產生 L<L<X1, X2>, L<X3>>,而 mp_join<L<L<X1, X2>, L<X3>>, S> 會產生 L<X1, X2, S, X3>

mp_join<L, S> 等同於 (且實作方式為) mp_apply<mp_append, mp_intersperse<L, mp_list<S>>>

mp_partition<L, P>

template<class L, template<class...> class P> using mp_partition = /*...*/;

mp_partition<L<T…​>, P>L 分割成兩個列表 L<U1…​>L<U2…​>,使得 mp_to_bool<P<T>> 對於 L<U1…​> 的元素為 mp_true,而對於 L<U2…​> 的元素為 mp_false。回傳 L<L<U1…​>, L<U2…​>>

mp_partition_q<L, Q>

template<class L, class Q> using mp_partition_q = mp_partition<L, Q::template fn>;

mp_partition 相同,但使用引用的元函數。

mp_sort<L, P>

template<class L, template<class...> class P> using mp_sort = /*...*/;

mp_sort<L, P> 根據嚴格弱排序 mp_to_bool<P<T, U>> 對列表 L 進行排序。

程式碼範例 79. 使用 mp_sort 對 std::ratio 值列表進行排序
#include <ratio>

using L1 = mp_list<std::ratio<1,2>, std::ratio<1,4>>;
using R1 = mp_sort<L1, std::ratio_less>; // mp_list<ratio<1,4>, ratio<1,2>>

mp_sort_q<L, Q>

template<class L, class Q> using mp_sort_q = mp_sort<L, Q::template fn>;

mp_sort 相同,但使用引用的元函數。

mp_nth_element_c<L, I, P>

template<class L, std::size_t I, template<class...> class P> using mp_nth_element_c =
    /*...*/;

回傳 mp_sort<L, P> 中位置 I 的元素。

mp_nth_element<L, I, P>

template<class L, class I, template<class...> class P> using mp_nth_element = /*...*/;

mp_nth_element_c 類似,但使用型別參數 II::value 必須是非負數。

mp_nth_element_q<L, I, Q>

template<class L, class I, class Q> using mp_nth_element_q =
    mp_nth_element<L, I, Q::template fn>;

mp_nth_element 類似,但使用引用的元函數。

mp_min_element<L, P>

template<class L, template<class...> class P> using mp_min_element = /*...*/;

mp_min_element<L, P> 根據排序 mp_to_bool<P<T, U>> 回傳列表 L 的最小元素。

它等同於 mp_fold<mp_rest<L>, mp_first<L>, F>,其中 F<T, U> 回傳 mp_if<P<T, U>, T, U>

在 C++17 中,支援將數值列表作為 L。在這種情況下,回傳的元素會使用 mp_value 包裝。

mp_min_element_q<L, Q>

template<class L, class Q> using mp_min_element_q = mp_min_element<L, Q::template fn>;

mp_min_element 相同,但使用引用的元函數。

mp_max_element<L, P>

template<class L, template<class...> class P> using mp_max_element = /*...*/;

mp_max_element<L, P> 根據排序 mp_to_bool<P<T, U>> 回傳列表 L 的最大元素。

它等同於 mp_fold<mp_rest<L>, mp_first<L>, F>,其中 F<T, U> 回傳 mp_if<P<U, T>, T, U>

在 C++17 中,支援將數值列表作為 L。在這種情況下,回傳的元素會使用 mp_value 包裝。

mp_max_element_q<L, Q>

template<class L, class Q> using mp_max_element_q = mp_max_element<L, Q::template fn>;

mp_max_element 相同,但使用引用的元函數。

mp_find<L, V>

template<class L, class V> using mp_find = /*...*/;

mp_find<L, V> 回傳類型 V 在列表 L 中的索引。它是 mp_size_t<I> 的別名,其中 IVL 中第一次出現的索引 (從零開始)。如果 L 不包含 V,則 mp_find<L, V>mp_size<L>

mp_find_if<L, P>

template<class L, template<class...> class P> using mp_find_if = /*...*/;

mp_find_f<L, P>mp_size_t<I> 的別名,其中 IL 中第一個滿足 mp_to_bool<P<T>>mp_true 的元素 T 的索引 (從零開始)。如果沒有這樣的元素,則 mp_find_if<L, P>mp_size<L>

mp_find_if_q<L, Q>

template<class L, class Q> using mp_find_if_q = mp_find_if<L, Q::template fn>;

mp_find_if 相同,但使用引用的元函數。

mp_reverse<L>

template<class L> using mp_reverse = /*...*/;

mp_reverse<L<T1, T2, …​, Tn>>L<Tn, …​, T2, T1>

範例 17. mp_reverse

L1

A1

A2

…​

An

mp_reverse<L1>

An

An-1

…​

A1

mp_fold<L, V, F>

template<class L, class V, template<class...> class F> using mp_fold = /*...*/;

mp_fold<L<T1, T2, …​, Tn>, V, F>F< F< F< F<V, T1>, T2>, …​>, Tn>,如果 L 是空的,則為 V

程式碼範例 80. 使用 mp_fold 將 std::ratio 值列表的內容相加
#include <ratio>

using L1 = mp_list<std::ratio<1,8>, std::ratio<1,4>, std::ratio<1,2>>;
using R1 = mp_fold<L1, std::ratio<0,1>, std::ratio_add>; // std::ratio<7,8>

mp_fold_q<L, V, Q>

template<class L, class V, class Q> using mp_fold_q =
    mp_fold<L, V, Q::template fn>;

mp_fold 相同,但使用引用的元函數。

mp_reverse_fold<L, V, F>

template<class L, class V, template<class...> class F> using mp_reverse_fold =
    /*...*/;

mp_reverse_fold<L<T1, T2, …​, Tn>, V, F>F<T1, F<T2, F<…​, F<Tn, V>>>>,如果 L 是空的,則為 V

mp_reverse_fold_q<L, V, Q>

template<class L, class V, class Q> using mp_reverse_fold_q =
    mp_reverse_fold<L, V, Q::template fn>;

mp_reverse_fold 相同,但使用引用的元函數。

mp_partial_sum<L, V, F>

template<class L, class V, template<class...> class F> using mp_partial_sum = /*...*/;

mp_partial_sum<L, V, F>mp_fold<L, V, F> 相似,但它不是回傳最終結果,而是回傳一個列表 (與 L 形式相同),其中包含 fold 的中間結果。mp_partial_sum 結果的最後一個元素與 mp_fold 的結果相同。

例如,mp_fold<mp_list<X1, X2, X3>, V, F>F<F<F<V, X1>, X2>, X3>,但 mp_partial_sum<mp_list<X1, X2, X3>, V, F>mp_list<F<V, X1>, F<F<V, X1>, X2>, F<F<F<V, X1>, X2>, X3>>

常見的情況是 Fmp_plus,在這種情況下,結果會包含 L 的部分和。

程式碼範例 81. 使用 mp_partial_sum
using L1 = mp_list_c<int, 1, 2, 3, 4>;
using R1 = mp_partial_sum<L1, mp_int<0>, mp_plus>; // mp_list_c<int, 1, 3, 6, 10>

mp_partial_sum_q<L, V, Q>

template<class L, class V, class Q> using mp_partial_sum_q =
    mp_partial_sum<L, V, Q::template fn>;

mp_partial_sum 相同,但使用引用的元函數。

mp_pairwise_fold<L, F>

template<class L, template<class...> class F> using mp_pairwise_fold = /*...*/;

mp_pairwise_fold<L, F> 會回傳一個與 L 形式相同的列表,其元素為將二元元函數 F 應用於 L 中每對相鄰元素的結果。也就是說,mp_pairwise_fold<L<T1, T2, T3>, F> 的結果會是 L<F<T1, T2>, F<T2, T3>>

結果會比原始列表少一個元素。如果 L 只有一個元素,結果會是空列表。如果 L 是空列表,結果也會是空列表。

程式碼範例 82. 使用 mp_pairwise_fold
template<class L> using is_increasing = mp_all_of<
    mp_pairwise_fold<L, mp_less>, mp_to_bool>;

mp_pairwise_fold_q<L, Q>

template<class L, class Q> using mp_pairwise_fold_q =
    mp_pairwise_fold<L, Q::template fn>;

mp_pairwise_fold 相同,但接受的是引用的元函數。

程式碼範例 83. 使用 mp_pairwise_fold_q
template<class L, template<class...> class P> using is_sorted =
    mp_none_of<mp_pairwise_fold_q<L, mp_bind<P, _2, _1>>, mp_to_bool>;

mp_sliding_fold<L, N, F>

template<class L, class N, template<class...> class F> using mp_sliding_fold = /*...*/;

mp_sliding_fold<L, N, F> 會回傳一個與 L 形式相同的列表,其元素為將 n 元元函數 F 應用於 L 中每個 n 元相鄰元素的結果。也就是說,mp_sliding_fold<L<T1, T2, T3, T4>, mp_size_t<3>, F> 的結果會是 L<F<T1, T2, T3>, F<T2, T3, T4>>

結果會比原始列表少 N-1 個元素。如果 L 的元素少於 N::value 個,結果會是空列表。

程式碼範例 84. 使用 mp_sliding_fold
template<class L, class N> using local_maximum =
    mp_sliding_fold<L, N, mp_max>;

mp_sliding_fold_q<L, N, Q>

template<class L, class N, class Q> using mp_sliding_fold_q =
    mp_sliding_fold<L, N, Q::template fn>;

mp_sliding_fold 相同,但接受的是引用的元函數。

程式碼範例 85. 使用 mp_sliding_fold_q
struct average { template<class... C> using fn = mp_int<mp_plus<C...>::value / sizeof...(C)>; };

template<class L, class N> using moving_average =
    mp_sliding_fold_q<L, N, average>;

mp_iterate<V, F, R>

template<class V, template<class...> class F, template<class...> class R>
    using mp_iterate = /*...*/;

mp_iterate<V, F, R> 會將 R 連續應用於 V,直到無法再應用為止,產生序列 VR<V>R<R<V>>R<R<R<V>>>…。

然後,它會回傳一個 mp_list,其元素是由將 F 應用於上述值序列所形成。也就是說,它會回傳 mp_list<F<V>, F<R<V>>, F<R<R<V>>>, …​>

在某種程度上,mp_iteratemp_reverse_fold 的反向操作。給定

template<class T, class U> struct cons {};
struct nil {};

mp_reverse_fold<mp_list<X1, X2, X3>, nil, cons> 會產生 cons<X1, cons<X2, cons<X3, nil>>>,當作為 V 傳遞給 mp_iterate<V, mp_first, mp_second> 時,會復原原始的 mp_list<X1, X2, X3>

程式碼範例 86. 使用 mp_iterate
struct X1 {};
struct X2 {};
struct X3 {};

using L1 = mp_list<X1, X2, X3>;
using R1 = mp_iterate<L1, mp_first, mp_rest>; // L1

template<class T, class U> struct cons {};
struct nil {};

using V2 = mp_reverse_fold<L1, nil, cons>; // cons<X1, cons<X2, cons<X3, nil>>>
using R2 = mp_iterate<V2, mp_first, mp_second>; // L1

struct Y1 {};
struct Y2 { using value_type = double; using next_type = Y1; };
struct Y3 { using value_type = float; using next_type = Y2; };
struct Y4 { using value_type = int; using next_type = Y3; };

template<class T> using value_type = typename T::value_type;
template<class T> using next_type = typename T::next_type;

using R3 = mp_iterate<Y4, mp_identity_t, next_type>; // mp_list<Y4, Y3, Y2, Y1>
using R4 = mp_iterate<Y4, value_type, next_type>; // mp_list<int, float, double>

mp_iterate_q<V, Qf, Qr>

template<class V, class Qf, class Qr> using mp_iterate_q =
    mp_iterate<V, Qf::template fn, Qr::template fn>;

mp_iterate 相同,但接受的是引用的元函數。

mp_unique<L>

template<class L> using mp_unique = /*...*/;

mp_unique<L> 會回傳一個與 L 形式相同的列表,並移除重複的元素。

mp_unique_if<L, P>

template<class L, template<class...> class P> using mp_unique_if = /*...*/;

mp_unique 相同,但當 mp_to_bool<P<T, U>>mp_true 時,兩個元素 TU 會被視為重複。

mp_unique_if_q<L, Q>

template<class L, class Q> using mp_unique_if_q =
    mp_unique_if<L, Q::template fn>;

mp_unique_if 相同,但接受的是引用的元函數。

mp_all_of<L, P>

template<class L, template<class...> class P> using mp_all_of =
    mp_bool< mp_count_if<L, P>::value == mp_size<L>::value >;

PL 的所有元素都成立時,mp_all_of<L, P>mp_true,否則為 mp_false。當 L 為空時,結果為 mp_true

mp_all_of_q<L, Q>

template<class L, class Q> using mp_all_of_q = mp_all_of<L, Q::template fn>;

mp_all_of 相同,但接受的是引用的元函數。

mp_none_of<L, P>

template<class L, template<class...> class P> using mp_none_of =
    mp_bool< mp_count_if<L, P>::value == 0 >;

PL 的任何元素都不成立時,mp_none_of<L, P>mp_true,否則為 mp_false。當 L 為空時,結果為 mp_true

mp_none_of_q<L, Q>

template<class L, class Q> using mp_none_of_q = mp_none_of<L, Q::template fn>;

mp_none_of 相同,但接受的是引用的元函數。

mp_any_of<L, P>

template<class L, template<class...> class P> using mp_any_of =
    mp_bool< mp_count_if<L, P>::value != 0 >;

PL 的至少一個元素成立時,mp_any_of<L, P>mp_true,否則為 mp_false。當 L 為空時,結果為 mp_false

mp_any_of_q<L, Q>

template<class L, class Q> using mp_any_of_q = mp_any_of<L, Q::template fn>;

mp_any_of 相同,但接受的是引用的元函數。

mp_for_each<L>(f)

template<class L, class F> constexpr F mp_for_each(F&& f);

mp_for_each<L>(f) 會依序對列表 L 的每個元素 T 使用 T() 呼叫 f

回傳 std::forward<F>(f)

程式碼範例 87. 使用 mp_for_each 和 C++14 lambda 來列印 tuple
template<class... T> void print( std::tuple<T...> const & tp )
{
    std::size_t const N = sizeof...(T);

    mp_for_each<mp_iota_c<N>>( [&]( auto I ){

        // I is mp_size_t<0>, mp_size_t<1>, ..., mp_size_t<N-1>

        std::cout << std::get<I>(tp) << std::endl;

    });
}

如果列表 L 的元素不是預設可建構的,您可以使用 mp_for_each<mp_transform<mp_identity, L>>,這會使用 mp_identity<T>() 而不是 T() 呼叫 f

mp_with_index<N>(i, f)

template<std::size_t N, class F>
  constexpr auto mp_with_index( std::size_t i, F && f )
    -> decltype(std::declval<F>()(std::declval<mp_size_t<0>>()));

mp_with_index<N>(i, f) 會使用 mp_size_t<i>() 呼叫 f 並回傳結果。i 必須小於 N。僅在 C++14 及更高版本上為 constexpr

template<class N, class F>
  constexpr auto mp_with_index( std::size_t i, F && f )
    -> decltype(std::declval<F>()(std::declval<mp_size_t<0>>()));

回傳 mp_with_index<N::value>(i, f)

程式碼範例 88. 使用 mp_with_index 和 C++14 lambda 來列印變體的活動元素
template<class... T> void print( std::variant<T...> const& v )
{
    mp_with_index<sizeof...(T)>( v.index(), [&]( auto I ) {

        // I is mp_size_t<v.index()>{} here

        std::cout << std::get<I>( v ) << std::endl;

    });
}

集合操作,<boost/mp11/set.hpp>

集合是元素唯一的列表。

mp_is_set<S>

template<class S> using mp_is_set = /*...*/;

如果 S 是集合,則 mp_is_set<S>mp_true,否則為 mp_false

mp_set_contains<S, V>

template<class S, class V> using mp_set_contains = /*...*/;

如果類型 V 是集合 S 的元素,則 mp_set_contains<S, V>mp_true,否則為 mp_false

mp_set_push_back<S, T…​>

template<class S, class... T> using mp_set_push_back = /*...*/;

對於 T…​ 中的每個 T1,如果 T1 還不是 S 的元素,則 mp_set_push_back<S, T…​> 會將 T1 附加到集合 S 的末尾。

mp_set_push_front<S, T…​>

template<class S, class... T> using mp_set_push_front = /*...*/;

mp_set_push_front<S, T…​> 會將 T…​S 尚未包含相同類型的元素插入到集合 S 的前端。

mp_set_union<L…​>

template<class... L> using mp_set_union = /*...*/;

mp_set_union<S, L…​>mp_set_push_back<S, T…​>,其中 T…​ 是列表 L…​ 的組合元素。mp_set_union<>mp_list<>

mp_set_intersection<S…​>

template<class... S> using mp_set_intersection = /*...*/;

mp_set_intersection<S…​> 會回傳一個集合,其中包含所有集合 S…​ 中都出現的元素。mp_set_intersection<>mp_list<>

mp_set_difference<L, S…​>

template<class L, class... S> using mp_set_difference = /*...*/;

mp_set_difference<L, S…​> 會移除列表 L 中出現在任何集合 S…​ 中的元素,並回傳結果。

映射操作,<boost/mp11/map.hpp>

映射表是列表的列表,內部列表至少有一個元素(鍵)。映射表的鍵必須是唯一的。

mp_is_map<M>

template<class M> using mp_is_map = /*...*/;

如果 M 是映射表,則 mp_is_map<M>mp_true,否則為 mp_false

mp_map_find<M, K>

template<class M, class K> using mp_map_find = /*...*/;

mp_map_find<M, K> 是映射表 M 中具有鍵 K 的元素的別名,如果沒有此元素,則為 void 的別名。

mp_map_contains<M, K>

template<class M, class K> using mp_map_contains =
    mp_not<std::is_same<mp_map_find<M, K>, void>>;

如果映射表 M 包含具有鍵 K 的元素,則 mp_map_contains<M, K>mp_true,否則為 mp_false

mp_map_insert<M, T>

template<class M, class T> using mp_map_insert =
    mp_if< mp_map_contains<M, mp_first<T>>, M, mp_push_back<M, T> >;

如果具有鍵 mp_first<T> 的元素尚未在 M 中,則將元素 T 插入到映射表 M 中。

mp_map_replace<M, T>

template<class M, class T> using mp_map_replace = /*...*/;

如果映射表 M 不包含具有鍵 mp_first<T> 的元素,則插入該元素 (使用 mp_push_back<M, T>);否則,以 T 取代現有元素。

mp_map_update<M, T, F>

template<class M, class T, template<class...> class F> using mp_map_update = /*...*/;

如果映射表 M 不包含具有鍵 mp_first<T> 的元素,則插入該元素 (使用 mp_push_back<M, T>);否則,以 L<X, F<X, Y…​>> 取代現有元素 L<X, Y…​>

程式碼範例 89. 使用 mp_map_update 來計算列表中類型的出現次數
template<class T, class U> using inc2nd = mp_int<U::value + 1>;

template<class M, class T> using count_types =
    mp_map_update<M, std::pair<T, mp_int<1>>, inc2nd>;

using L1 = mp_list<float, char, float, float, float, float, char, float>;

using R1 = mp_fold<L1, std::tuple<>, count_types>;
// std::tuple<std::pair<float, mp_int<6>>, std::pair<char, mp_int<2>>>

mp_map_update_q<M, T, Q>

template<class M, class T, class Q> using mp_map_update_q =
    mp_map_update<M, T, Q::template fn>;

mp_map_update 相同,但接受的是引用的元函數。

mp_map_erase<M, K>

template<class M, class K> using mp_map_erase = /*...*/;

如果映射表 M 包含具有鍵 K 的元素,則會移除它。

mp_map_keys<M>

template<class M> using mp_map_keys = mp_transform<mp_first, M>;

mp_map_keys<M> 會回傳 M 的鍵的列表。當 M 是有效的映射表時,鍵是唯一的,因此結果是一個集合。

輔助元函式,<boost/mp11/function.hpp>

mp_void<T…​>

template<class... T> using mp_void = void;

與 C++17 中的 std::void_t 相同。

mp_and<T…​>

template<class... T> using mp_and = /*...*/;

mp_and<T…​> 會依序將 mp_to_bool 應用於 T…​ 中的類型。如果應用程式的結果為 mp_false,則 mp_and 會回傳 mp_false。如果應用程式造成替代失敗,則會回傳 mp_false。如果所有結果都是 mp_true,則會回傳 mp_truemp_and<>mp_true

程式碼範例 90. mp_and 的行為
using R1 = mp_and<mp_true, mp_true>;   // mp_true

using R2 = mp_and<mp_false, void>;     // mp_false, void is not reached

using R3 = mp_and<mp_false, mp_false>; // mp_false

using R4 = mp_and<void, mp_true>;      // mp_false (!)

mp_all<T…​>

template<class... T> using mp_all = /*...*/;

如果 T…​ 中所有類型 Ump_to_bool<U> 都是 mp_true,則 mp_all<T…​>mp_true,否則為 mp_false。與 mp_and 相同,但不執行短路求值。mp_and<mp_false, void>mp_false,但 mp_all<mp_false, void> 會產生錯誤,因為 void 沒有巢狀的 value。好處是 mp_all 可能更快,且不會像 mp_and 那樣遮罩替代失敗。

程式碼範例 91. mp_all 的行為
using R1 = mp_all<mp_true, mp_true>;   // mp_true

using R2 = mp_all<mp_false, void>;     // compile-time error

using R3 = mp_all<mp_false, mp_false>; // mp_false

using R4 = mp_all<void, mp_true>;      // compile-time error

mp_or<T…​>

template<class... T> using mp_or = /*...*/;

mp_or<T…​> 會依序將 mp_to_bool 應用於 T…​ 中的類型。如果應用程式的結果為 mp_true,則 mp_or 會回傳 mp_true。如果所有結果都是 mp_false,則會回傳 mp_falsemp_or<>mp_false

程式碼範例 92. mp_or 的行為
using R1 = mp_or<mp_true, mp_false>;   // mp_true

using R2 = mp_or<mp_true, void>;       // mp_true, void is not reached

using R3 = mp_or<mp_false, mp_false>;  // mp_false

using R4 = mp_or<void, mp_true>;       // compile-time error

mp_any<T…​>

template<class... T> using mp_any = /*...*/;

如果 T…​ 中有任何類型 Ump_to_bool<U>mp_true,則 mp_any<T…​>mp_true,否則為 mp_false。與 mp_or 相同,但不執行短路求值。

程式碼範例 93. mp_any 的行為
using R1 = mp_any<mp_true, mp_false>;  // mp_true

using R2 = mp_any<mp_true, void>;      // compile-time error

using R3 = mp_any<mp_false, mp_false>; // mp_false

using R4 = mp_any<void, mp_true>;      // compile-time error

mp_same<T…​>

template<class... T> using mp_same = /*...*/;

如果 T…​ 中的所有類型都是相同的類型,則 mp_same<T…​>mp_true,否則為 mp_falsemp_same<>mp_true

mp_similar<T…​>

template<class... T> using mp_similar = /*...*/;

如果 T…​ 中的所有類型都是相同的類型,或是相同類別範本的實例化 (其參數都是類型),則 mp_similar<T…​>mp_true,否則為 mp_falsemp_similar<>mp_true

程式碼範例 94. mp_similar
using R1 = mp_similar<void>;                        // mp_true
using R2 = mp_similar<void, void>;                  // mp_true
using R3 = mp_similar<void, void, void>;            // mp_true
using R4 = mp_similar<void, void, float>;           // mp_false

template<class T> struct X;
template<class... T> struct Y;

using R5 = mp_similar<X<int>, X<void>, X<float>>;   // mp_true
using R6 = mp_similar<Y<>, Y<void>, Y<void, void>>; // mp_true
using R7 = mp_similar<X<void>, Y<void>>;            // mp_false

mp_plus<T…​>

template<class... T> using mp_plus = /*...*/;

mp_plus<T…​> 是一個整數常數類型,其值為 T…​ 中所有類型 UU::value 的總和。mp_plus<>mp_int<0>

mp_less<T1, T2>

template<class T1, class T2> using mp_less = /*...*/;

T1::value 的數值小於 T2::value 的數值時,mp_less<T1, T2>mp_true,否則為 mp_false

(請注意,當在帶正負號和不帶正負號的類型之間比較時,這不一定與 T1::value < T2::value 相同;-1 < 1ufalse,但 mp_less<mp_int<-1>, mp_size_t<1>>mp_true。)

mp_min<T1, T…​>

template<class T1, class... T> using mp_min = mp_min_element<mp_list<T1, T...>, mp_less>;

mp_min<T…​> 會回傳 T…​ 中具有最低 U::value 的類型 U

mp_max<T1, T…​>

template<class T1, class... T> using mp_max = mp_max_element<mp_list<T1, T...>, mp_less>;

mp_max<T…​> 會回傳 T…​ 中具有最高 U::value 的類型 U

綁定,<boost/mp11/bind.hpp>

mp_arg<I>

template<std::size_t I> struct mp_arg;

mp_arg<I> 是一個引用的元函數,其巢狀範本 fn<T…​> 會回傳 T…​ 中從零開始的第 I 個元素。

_1, …​, _9

using _1 = mp_arg<0>;
using _2 = mp_arg<1>;
using _3 = mp_arg<2>;
using _4 = mp_arg<3>;
using _5 = mp_arg<4>;
using _6 = mp_arg<5>;
using _7 = mp_arg<6>;
using _8 = mp_arg<7>;
using _9 = mp_arg<8>;

_1_9 是佔位符類型,相當於 boost::bind 的佔位符。

mp_bind<F, T…​>

template<template<class...> class F, class... T> struct mp_bind;

mp_bind<F, T…​> 是一個引用的元函數,它實作了基於類型的等效 boost::bind。其巢狀範本 fn<U…​> 會回傳 F<V…​>,其中 V…​T…​,佔位符會被 U…​ 的對應元素取代,並且 mp_bindmp_bind_frontmp_bind_back 運算式會被它們針對 U…​ 的對應求值取代。

例如,mp_bind<F, int, _2, mp_bind<G, _1>>::fn<float, void>F<int, void, G<float>>

mp_bind_q<Q, T…​>

template<class Q, class... T> using mp_bind_q = mp_bind<Q::template fn, T...>;

mp_bind 相同,但接受的是引用的元函數。

mp_bind_front<F, T…​>

template<template<class...> class F, class... T> struct mp_bind_front;

mp_bind_front<F, T…​> 會將 F 最左邊的引數繫結到 T…​。其巢狀範本 fn<U…​> 會回傳 F<T…​, U…​>

mp_bind_front_q<Q, T…​>

template<class Q, class... T> using mp_bind_front_q =
    mp_bind_front<Q::template fn, T...>;

mp_bind_front 類似,但接受的是一個被引用的元函數。

mp_bind_back<F, T…​>

template<template<class...> class F, class... T> struct mp_bind_back;

mp_bind_back<F, T…​>F 的最右側參數綁定到 T…​。其巢狀樣板 fn<U…​> 會回傳 F<U…​, T…​>

mp_bind_back_q<Q, T…​>

template<class Q, class... T> using mp_bind_back_q =
    mp_bind_back<Q::template fn, T...>;

mp_bind_back 類似,但接受的是一個被引用的元函數。

Lambda 表達式,<boost/mp11/lambda.hpp>

mp_lambda<T>

template<class T> using mp_lambda = /*...*/;

mp_lambda<T> 是一個被引用的元函數,其巢狀樣板 fn<U…​> 會回傳一個類型 V,其語法定義與 T 相同,只是 T 中出現的佔位符會被 U…​ 中對應的元素所取代。

例如,mp_lambda<std::pair<_1, _2*>>::fn<int, char>std::pair<int, char*>

當類別樣板使用非類型樣板參數進行實例化時,所產生的 T 組成部分內部不會發生替換。

注意
在 GCC 4.8 中,編譯器錯誤會導致回傳類型 V 中的 constvolatile 限定詞被剝除(除非它們套用至函式或成員函式類型)。
注意
由於編譯器的限制,VS2013 及更早版本不支援 mp_lambda

整數序列,<boost/mp11/integer_sequence.hpp>

integer_sequence<T, I…​>

template<class T, T... I> struct integer_sequence
{
};

integer_sequence<T, I…​> 持有一個類型為 T 的整數序列。與 C++14 的 std::integer_sequence 相同。

make_integer_sequence<T, N>

template<class T, T N> using make_integer_sequence = /*...*/;

make_integer_sequence<T, N>integer_sequence<T, 0, 1, …​, N-1>。與 C++14 的 std::make_integer_sequence 相同。

index_sequence<I…​>

template<std::size_t... I> using index_sequence = integer_sequence<std::size_t, I...>;

index_sequence<I…​>integer_sequence<size_t, I…​> 的別名。與 C++14 的 std::index_sequence 相同。

make_index_sequence<N>

template<std::size_t N> using make_index_sequence =
    make_integer_sequence<std::size_t, N>;

make_index_sequence<N>index_sequence<0, 1, …​, N-1>。與 C++14 的 std::make_index_sequence 相同。

index_sequence_for<T…​>

template<class... T> using index_sequence_for =
    make_integer_sequence<std::size_t, sizeof...(T)>;

index_sequence_for<N>make_index_sequence<sizeof…​(T)>。與 C++14 的 std::index_sequence_for 相同。

元組操作,<boost/mp11/tuple.hpp>

tuple_apply(f, tp)

template<class F, class Tp> constexpr /*...*/ tuple_apply(F&& f, Tp&& tp);

tuple_apply(f, tp) 會針對 0 到 N-1J 回傳 std::forward<F>(f)(std::get<J>(std::forward<Tp>(tp))…​),其中 Nstd::tuple_size<typename std::remove_reference<Tp>::type>::value。與 C++17 中的 std::apply 相同。

construct_from_tuple<T>(tp)

template<class T, class Tp> T construct_from_tuple(Tp&& tp);

construct_from_tuple<T>(tp) 會針對 0 到 N-1J 回傳 T(std::get<J>(std::forward<Tp>(tp))…​),其中 Nstd::tuple_size<typename std::remove_reference<Tp>::type>::value。與 C++17 中的 std::make_from_tuple 相同。函式名稱與 C++17 的函式名稱不符,以避免在兩者都可見或在未限定呼叫中產生歧義。

tuple_for_each(tp, f)

template<class Tp, class F> constexpr F tuple_for_each(Tp&& tp, F&& f);

tuple_for_each(tp, f) 會依序將函式物件 f 套用至 tp 的每個元素,方法是針對 0 到 N-1J 計算表達式 f(std::get<J>(std::forward<Tp>(tp))),其中 Nstd::tuple_size<typename std::remove_reference<Tp>::type>::value

回傳 std::forward<F>(f)

tuple_transform(f, tp…​)

template<class F, class... Tp> constexpr /*...*/ tuple_transform(F const& f, Tp&&... tp);

tuple_transform(f, tp…​) 接受一個函式物件 f,後接一個或多個長度相等的 tuple(std::tuplestd::pairstd::array 皆被視為 tuple)。

可呼叫的 f 必須接受與 tuple 數量一樣多的參數。函式物件會依序使用每個 tuple 的第一個元素、每個 tuple 的第二個元素等進行呼叫,就如同針對 0 到 N-1J 計算表達式 f(std::get<J>(std::forward<Tp>(tp))…​),其中 N 是 tuple 的長度。

處理 tuple 元素的順序未指定。

結果會以 std::tuple<T…​> 的形式回傳,其中 T…​ 會從 f 的回傳值推斷(會保留左值參考,而右值參考則依值回傳)。

便利標頭,<boost/mp11.hpp>

方便使用的標頭 <boost/mp11.hpp> 包含了此參考文件中先前列出的所有標頭。

MPL 支援,<boost/mp11/mpl.hpp>

當包含標頭 <boost/mp11/mpl.hpp> 時,會定義必要的支援基礎結構,使 mp_liststd::tuple 成為有效的 MPL 序列。

注意
<boost/mp11.hpp> 不包含 mpl.hpp

也可以只透過包含 <boost/mp11/mpl_list.hpp> 來啟用對 mp_list 的支援,以及透過包含 <boost/mp11/mpl_tuple.hpp> 來啟用對 std::tuple 的支援。之所以可能需要這樣做,是因為某些程式庫(例如 Boost.Fusion)包含其自己的針對 std::tuple 的 MPL 支援,這與 Mp11 的支援相衝突。

程式碼範例 95. 將現有的 MPL 序列轉換為 mp_list
using L = mpl::copy<Sequence, mpl::back_inserter<mp11::mp_list<>>>::type;

此文件版權歸

  • Copyright 2017-2019 Peter Dimov

  • Copyright 2017 Bjørn Reese

並依 Boost 軟體授權,1.0 版 發佈。

「Simple C++11 metaprogramming」文章已由 Glen Fernandes 慷慨地轉換為 Asciidoc 格式,以便納入本文件中。