Boost hana:強大的 compile-time library(一)
最近因為各種原因發現了 boost hana 這個 library,haha 是 boost 一個 meta programming 的 library。Hana 運用了 C++14 的功能,具有相當優秀的編譯期速度,且編寫起來相對直觀,甚至可以有 macro 把對 struct 的每個物件做 iteration,非常的強大。這系列的文章將會包含 hana 設計的發想來源、一些使用方式以及如何對 struct 的每個物件做 iteration。
經典作法:template specialization
在 C++ 裡面,有一種空的 class 可以拿來承載 type 或是 compile time constant (constexpr
) 的資訊。透過 template specialization,可以拿這些 class 做運算之後,得到新的 class,再從裡面拿出需要的 constexpr 進一步運用。一個最常見這類 class 的就是 C++ 之後 11 標準化的 integral_constant。
1#include <type_traits>
2template<class T, T v>
3struct integral_constant;
T
跟 v
)。其 size 爲 1(因為 C++ 要求 size 不能為 0),因此,雖然 programmer 可以 instantiate 這個 class,但是好像用處也不大:
1cout << sizeof(integral_constant<int, 1>) << endl;
2integral_constant<int, 1> useless{};
1// vallina template
2template<class A, class B>
3struct add_integral {};
4// specialized template
5template<int a, int b>
6struct add_integral<
7 integral_constant<int, a>,
8 integral_constant<int, b>
9> {
10 constexpr int value = a+b;
11};
integral_constant
,繼續進行運算。
1// x = 4
2constexpr int x = add_integral<
3 integral_constant<int, 1>,
4 integral_constant<int, 3>
5>::value;
6// y = 8
7constexpr int y = add_integral<
8 integral_constant<int, x>,
9 integral_constant<int, x>
10>::value;
constexpr
了,還需要 integral_constant
這種囉唆的東西呢?這件事情我們 delay 到下下段討論,先來講 boost hana 的一些設計基本邏輯。
1constexpr int a = 1;
2constexpr int b = 1;
3constexpr int c = a+b;
4constexpr int d = c+c;
Hana 的作法:function overload
前面提到,雖然 programmer 可以 instantiate 一個 integral_constant
,但是好像用處也不大,但是 hana 的想法卻是不同。hana 發現可以用這個 object 搭配 overload 來做運算,首先我們需要一個對 integral_constant
操作的 function,甚至可以定義一般的 operator+
:
1template<int a, int b>
2integral_constant<int, a+b> operator+(
3 integral_constant<int, a>,
4 integral_constant<int, b>
5) {
6 return integral_constant<int, a+b>{};
7}
decltype(d)
才把型別資訊 value
取出來用。
1integral_constant<int, 1> a{};
2integral_constant<int, 3> b{};
3auto c = a+b; // c is of type integral_constant<int, 3>
4auto d = c+c; // d is of type integral_constant<int, 8>
5constexpr int value = decltype(d)::value; // value = 8
為什麼需要 integral_constant?
這邊回來講一下前面延後講的 integral_constant
的用法,一個常見的用法是把他當作一個 tag,這樣我們就可以在 compile time 去決定要 call 哪個版本的函數,例如說下面這個例子,f2
跟 f3
的函數回傳的型別不同,所以沒辦法編譯成功。
1array<int, 2> f2() { return {99,99}; }
2array<int, 3> f3() { return {1,1,1}; }
3template<int x>
4array<int, x> f() {
5 if (x == 2) {
6 return f2();
7 } else if (x == 3) {
8 return f3();
9 }
10}
x
是 constexpr
,還是不能編譯,integral_constant
就能派上用場,用 overload 的方式來選出想要的函數。
1array<int, 2> f_inner(integral_constant<int, 2>) { return {99,99}; }
2array<int, 3> f_inner(integral_constant<int, 3>) { return {1,1,1}; }
3template<int x>
4array<int, x> f() {
5 return f_inner(integral_constant<int, x>{});
6}
if constexpr
輕鬆達成)
1template<int x>
2array<int, x> f() {
3 if constexpr (x == 2) {
4 return f2();
5 } else if constexpr (x == 3) {
6 return f3();
7 }
8}
總結
其實這篇文章還沒講到 boost hana 到底可以作到哪些神奇的事情,因為前情提要不小心打太多了,就從下一篇開始講吧。
系列文連結
-
Boost hana:強大的 compile-time library(一)
- Boost hana:強大的 compile-time library(一)