概述
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_t
、std::is_const
、mp_second
、mp_push_front
、mp_list
、std::tuple
、std::pair
、std::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;
該元函式應該表示對整數型別 T
和 U
進行算術運算的結果,例如 t + u
。我們想要測試 result<T, U>
是否為 T
和 U
的各種組合提供正確的結果,因此我們編寫了函式
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
,而 F
是 mp_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_each
。tuple_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
。我們可以定義一個巢狀的 type
為 common_tuple<std::tuple<T1…>, std::tuple<T2…>>
,它仍然可以在所有有效的情況下運作。然而,透過讓 mp_defer
定義 type
,我們使我們的特化成為SFINAE友善的。
也就是說,當我們的 common_tuple
導致替代失敗而不是硬性錯誤時,mp_defer
將不會定義巢狀的 type
,而定義為 typename common_type<…>::type
的 common_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>>
為我們提供了 E1
和 E2
的串接,並刪除了重複項;然後我們透過 mp_push_front
將 common_type_t<T1, T2>
新增到前端;最後,我們將結果的 mp_list
mp_rename
為 expected
。
修正 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_size
、tuple_element
和 get
的類型),而我們的實作僅適用於 tuple
和 pair
。例如,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::pair
和 std::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>
,其中 N
是 tuple_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>
會對 L1
和 L2
的元素執行兩個巢狀迴圈,將 F
應用於兩個變數並收集結果。在我們的例子中,L1
由單個元素 T
組成,因此只剩下第二個迴圈(遍歷 mp_iota<N>
,其中 N
是 tuple_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
有一個限制:除非函式的所有可能應用都具有相同的回傳類型,否則它無法回傳結果。例如,如果 v1
和 v2
都是 std::variant<short, int, float>
類型,
std::visit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
將無法編譯,因為 x + y
的結果可以是 int
或 float
,取決於 v1
和 v2
所保留的內容。
已經存在一種可以保留 int
或 float
的類型,令人驚訝地稱為 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
相同,除了它將結果轉換為共同類型 R
。R
應該是 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_q
與 mp_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_fold
,mp_pairwise_fold
的泛化 (由 Braden Ganetsky 貢獻) -
新增
mp_slice
(感謝 Braden Ganetsky) -
為
mp_min_element
、mp_max_element
新增值列表支援。 -
為
mp_transform
新增有限的值列表支援。
1.83.0 版的變更
-
為
mp_from_sequence
、mp_iota
、mp_iota_c
新增偏移/起始參數。 -
新增
mp_value
、mp_list_v
、mp_rename_v
、mp_is_value_list
。 -
為
<boost/mp11/list.hpp>
中的基本類型新增值列表支援。 -
為
mp_repeat
、mp_fill
、mp_at
、mp_back
、mp_take
、mp_pop_back
、mp_drop
、mp_insert
、mp_erase
新增值列表支援。
1.79.0 版的變更
-
新增
mp_valid_and_true
(由 Dmitry Arkhipov 貢獻)
1.78.0 版的變更
-
為
mp_compose
新增 n 元函式支援 (由 Dmitry Arkhipov 貢獻)
1.77.0 版的變更
-
新增
mp_intersperse
、mp_split
、mp_join
1.75.0 版的變更
-
新增
mp_pairwise_fold
(由 Barry Revzin 建議) -
移除
mp_invoke
(使用mp_invoke_q
)
1.74.0 版的變更
-
改善大型
N
的mp_with_index<N>
的編譯效能 -
新增
tuple_transform
(由 Hans Dembinski 貢獻)
1.73.0 版的變更
-
新增
mp_unique_if
(由 Kris Jusiak 貢獻) -
新增
mp_flatten
-
新增
mp_rotate_left
、mp_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_union
、mp_set_intersection
、mp_set_difference
-
新增
mp_not_fn
-
新增
mp_transform_first
、mp_transform_second
、mp_transform_third
-
新增
mp_filter
-
新增
mp_eval_if_not
、mp_eval_or
、mp_valid_q
-
新增
mp_back
、mp_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 整數常數型別 T
,T::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::tuple
或 std::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
。
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
。
using L1 = mp_list<>;
using R1 = mp_size<L1>; // mp_size_t<0>
using L2 = std::pair<int, int>;
using R2 = mp_size<L2>; // mp_size_t<2>
using L3 = std::tuple<float>;
using R3 = mp_size<L3>; // mp_size_t<1>
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
。
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 下支援值列表作為 L1
或 L2
。當將值指派給型別時,會將它們包裝在 mp_value
中。當將型別指派給值時,會使用 T::value
解包它們。
using L1 = std::tuple<long>;
using L2 = mp_list<int, float>;
using R1 = mp_assign<L1, L2>; // std::tuple<int, float>
using L1 = std::pair<long, char>;
using L2 = mp_list<int, float>;
using R1 = mp_assign<L1, L2>; // std::pair<int, float>
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
。
using L1 = std::tuple<int, float>;
using R1 = mp_clear<L1>; // std::tuple<>
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
中。
using L1 = std::pair<int, float>;
using R1 = mp_front<L1>; // int
using L2 = std::tuple<float, double, long double>;
using R2 = mp_front<L2>; // float
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_front<L3>; // char[1]
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
。
using L1 = std::tuple<float, double, long double>;
using R1 = mp_pop_front<L1>; // std::tuple<double, long double>
using L2 = mp_list<void>;
using R2 = mp_pop_front<L2>; // mp_list<>
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_first
是 mp_front
的另一個名稱。
mp_rest<L>
template<class L> using mp_rest = mp_pop_front<L>;
mp_rest
是 mp_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
中。
using L1 = std::pair<int, float>;
using R1 = mp_second<L1>; // float
using L2 = std::tuple<float, double, long double>;
using R2 = mp_second<L2>; // double
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_second<L3>; // char[2]
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
中。
using L1 = std::tuple<float, double, long double>;
using R1 = mp_third<L1>; // long double
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
using R2 = mp_third<L2>; // char[3]
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…>
。
using L1 = std::tuple<double, long double>;
using R1 = mp_push_front<L1, float>; // std::tuple<float, double, long double>
using L2 = mp_list<void>;
using R2 = mp_push_front<L2, char[1], char[2]>; // mp_list<char[1], char[2], void>
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…>
。
using L1 = std::tuple<double, long double>;
using R1 = mp_push_back<L1, float>; // std::tuple<double, long double, float>
using L2 = mp_list<void>;
using R2 = mp_push_back<L2, char[1], char[2]>; // mp_list<void, char[1], char[2]>
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>…>
。
using L1 = std::pair<double, long double>;
using R1 = mp_rename<L1, std::tuple>; // std::tuple<double, long double>
using L2 = std::tuple<void>;
using R2 = mp_rename<L2, mp_list>; // mp_list<void>
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
相同。)
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
相同,但採用引號中繼函式。
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。
對於值列表 L
,mp_rename_v<L<A…>, Y>
是 Y<A…>
。
對於型別列表 L
,mp_rename_v<L<T…>, Y>
是 Y<T::value…>
的別名。
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
中混合型別列表和值列表。
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>
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…>
。
using L1 = std::pair<int, float>;
using R1 = mp_replace_front<L1, void>; // std::pair<void, float>
using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_front<L2, void>; // std::tuple<void, double, long double>
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]>;
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_first
是 mp_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…>
。
using L1 = std::pair<int, float>;
using R1 = mp_replace_second<L1, void>; // std::pair<int, void>
using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_second<L2, void>; // std::tuple<float, void, long double>
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]>;
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…>
。
using L1 = std::tuple<float, double, long double>;
using R1 = mp_replace_third<L1, void>; // std::tuple<float, double, void>
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]>;
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_first
是 mp_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++ 標準所述),它只會回傳相同的型別。它本身就很有用,也可用作將型別作為值傳遞給函式的型別包裝器。
template<class T> using addp_if_not_ref =
typename mp_if<std::is_reference<T>, mp_identity<T>, std::add_pointer<T>>::type;
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
的別名。否則,結果會是替換失敗。
using R1 = mp_if_c<true, int, void>; // int
using R2 = mp_if_c<false, int, void>; // void
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
類似,但第一個引數是型別。
using R1 = mp_if<mp_true, int, void>; // int
using R2 = mp_if<mp_false, int, void>; // void
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 = /*...*/;
當 C
為 true
時,mp_eval_if_c<C, T, F, U…>
是 T
的別名,否則為 F<U…>
。其目的是避免在條件為 true
時評估 F<U…>
,因為在這種情況下它可能無效。
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
類似,但第一個引數是型別。
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
。
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
。
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)
是替換失敗,則結果也會是替換失敗。)
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…>
。
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
轉換為引號中繼函式。
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…>
會評估引號中繼函式的巢狀樣板 fn
。mp_invoke_q<mp_quote<F>, T…>
會回傳 F<T…>
。
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>>>;
template<class T> using is_const_and_volatile =
mp_apply<mp_all, mp_transform_q<mp_bind_back<mp_invoke_q, T>, LQ>>;
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>
是一個引號中繼函式,它會依序將 F1
、F2
、…、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…>
。
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*>
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
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mp_transform_q<Q, L…>
template<class Q, class... L> using mp_transform_q = mp_transform<Q::template fn, L...>;
如同 mp_transform
,但接受引號中繼函式。
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>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>
,並回傳結果,其中 Ti
是 Li
的對應元素。
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>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
,但接受引號中繼函式。
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>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
元素,並回傳結果,其中 Ti
是 Li
的對應元素。
另請參閱 mp_copy_if
和 mp_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
,但接受引號中繼函式。
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
取代。
using L1 = std::tuple<void, int, float>;
using R1 = mp_fill<L1, double>; // std::tuple<double, double, double>
using L1 = std::pair<int, float>;
using R1 = mp_fill<L1, void>; // std::pair<void, void>
using L1 = mp_list_v<true, false>;
using R1 = mp_fill<L1, mp_int<7>>; // mp_list_v<7, 7>
|
|
|
|
|
|
|
|
|
|
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>
,其中 N
是 mp_to_bool<P<T>>
為 mp_true
的 L
元素 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 = /*...*/;
當 L1
以 L2
開頭時,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
相同形式的清單,其中包含 L
的 N
個串連複本。
在 C++17 下支援值列表作為 L
。
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<>>
。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
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
的形式相同)(其中 n
是 L
的長度)。
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
。
|
|
|
|
|
|
|
|
|
|
|
mp_drop<L, N>
template<class L, class N> using mp_drop = /*...*/;
與 mp_drop_c
相同,但具有型別引數 N
。N::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>>
的別名。
|
|
|
|
|
|
|
|
|
|
mp_iota<N, F>
template<class N, class F = mp_int<0>> using mp_iota = /*...*/;
與 mp_iota_c
相同,但使用型別參數 N
和 F
。N::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>>
,其中 T
是 N::value
的型別。
|
|
|
|
|
|
|
|
|
|
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
相同,但使用型別參數 I
。I::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
。
|
|
|
|
|
|
|
|
|
|
|
mp_take<L, N>
template<class L, class N> using mp_take = /*...*/;
與 mp_take_c
相同,但使用型別參數 N
。N::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
。
|
|
|
|
|
|
|
|
|
|
|
|
|
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
相同,但使用型別參數 I
和 J
。I::value
和 J::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…
。
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
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
。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
相同,但使用型別參數 I
和 J
。
mp_replace<L, V, W>
template<class L, class V, class W> using mp_replace = /*...*/;
將 L
中所有 V
元素替換為 W
並回傳結果。
|
|
|
|
|
|
|
|
|
|
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_true
的 T
元素替換為 W
並回傳結果。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
相同,但使用型別參數 I
。I::value
必須是非負數。
mp_rotate_left_c<L, N>
template<class L, std::size_t N> using mp_rotate_left_c = /*...*/;
將列表 L
的前 N % M
個元素移動到尾端,其中 M
是 L
的大小。空的列表保持不變。
mp_rotate_left<L, N>
template<class L, class N> using mp_rotate_left = /*...*/;
與 mp_rotate_left_c
相同,但使用型別參數 N
。N::value
必須是非負數。
mp_rotate_right_c<L, N>
template<class L, std::size_t N> using mp_rotate_right_c = /*...*/;
將列表 L
的後 N % M
個元素移動到前端,其中 M
是 L
的大小。空的列表保持不變。
mp_rotate_right<L, N>
template<class L, class N> using mp_rotate_right = /*...*/;
與 mp_rotate_right_c
相同,但使用型別參數 N
。N::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
的元素) 替換為它們的元素並回傳結果。
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_join
是 mp_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
進行排序。
#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
類似,但使用型別參數 I
。I::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>
的別名,其中 I
是 V
在 L
中第一次出現的索引 (從零開始)。如果 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>
的別名,其中 I
是 L
中第一個滿足 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>
。
|
|
|
|
|
|
|
|
|
|
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
。
#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>>
。
常見的情況是 F
為 mp_plus
,在這種情況下,結果會包含 L
的部分和。
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
是空列表,結果也會是空列表。
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
相同,但接受的是引用的元函數。
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
個,結果會是空列表。
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
相同,但接受的是引用的元函數。
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
,直到無法再應用為止,產生序列 V
、R<V>
、R<R<V>>
、R<R<R<V>>>
…。
然後,它會回傳一個 mp_list
,其元素是由將 F
應用於上述值序列所形成。也就是說,它會回傳 mp_list<F<V>, F<R<V>>, F<R<R<V>>>, …>
。
在某種程度上,mp_iterate
是 mp_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>
。
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
時,兩個元素 T
和 U
會被視為重複。
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 >;
當 P
對 L
的所有元素都成立時,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 >;
當 P
對 L
的任何元素都不成立時,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 >;
當 P
對 L
的至少一個元素成立時,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)
。
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)
。
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…>
。
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_true
。mp_and<>
為 mp_true
。
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…
中所有類型 U
的 mp_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
那樣遮罩替代失敗。
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_false
。mp_or<>
為 mp_false
。
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…
中有任何類型 U
的 mp_to_bool<U>
為 mp_true
,則 mp_any<T…>
為 mp_true
,否則為 mp_false
。與 mp_or
相同,但不執行短路求值。
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_false
。mp_same<>
為 mp_true
。
mp_similar<T…>
template<class... T> using mp_similar = /*...*/;
如果 T…
中的所有類型都是相同的類型,或是相同類別範本的實例化 (其參數都是類型),則 mp_similar<T…>
為 mp_true
,否則為 mp_false
。mp_similar<>
為 mp_true
。
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…
中所有類型 U
的 U::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 < 1u
為 false
,但 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_bind
、mp_bind_front
和 mp_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 中的 const 和 volatile 限定詞被剝除(除非它們套用至函式或成員函式類型)。 |
注意
|
由於編譯器的限制,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-1
的 J
回傳 std::forward<F>(f)(std::get<J>(std::forward<Tp>(tp))…)
,其中 N
是 std::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-1
的 J
回傳 T(std::get<J>(std::forward<Tp>(tp))…)
,其中 N
是 std::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-1
的 J
計算表達式 f(std::get<J>(std::forward<Tp>(tp)))
,其中 N
是 std::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::tuple
、std::pair
和 std::array
皆被視為 tuple)。
可呼叫的 f
必須接受與 tuple 數量一樣多的參數。函式物件會依序使用每個 tuple 的第一個元素、每個 tuple 的第二個元素等進行呼叫,就如同針對 0 到 N-1
的 J
計算表達式 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_list
和 std::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 的支援相衝突。
using L = mpl::copy<Sequence, mpl::back_inserter<mp11::mp_list<>>>::type;
附錄 A:版權、許可和致謝
此文件版權歸
-
Copyright 2017-2019 Peter Dimov
-
Copyright 2017 Bjørn Reese
並依 Boost 軟體授權,1.0 版 發佈。
「Simple C++11 metaprogramming」文章已由 Glen Fernandes 慷慨地轉換為 Asciidoc 格式,以便納入本文件中。