meta program - 实例化

EXAMPLE ONE

template <typename T, T b, uint32_t e>
struct pow : std::integral_constant<decltype(b * 1), b * pow<T, b, e - 1>::value> {};

template <typename T, T b>
struct pow<T, b, 0> : std::integral_constant<decltype(b * 1), T(1)> {};

template <uint32_t e>
using pow_two_with_exp = pow<uint64_t, 2, e>;

template<size_t N, size_t exp>
struct SizeOfBits {
    static  uint32_t value = (N / pow_two_with_exp<exp>::value) == 0 ? exp:SizeOfBits<N,exp+1>::value;
};

这个meta program用来计算N占用多少个bit表示。
乍看起来没有什么问题,因为对于<N,exp>,计算value时:如果\(2^{exp}>N\)时, 可以得知使用exp位可以表示N;否则测试<N,exp+1>
不过这段代码实际的问题是: 1.条件运算符会实例化所有的分支; 2.使用了::运算符访问类中的成员会促使类的所有成员被实例化。
可以看到这段代码会导致编译期模板递归超过限制


所以,可以将模板改写成这样:

template<size_t N, size_t exp=0>
struct SizeOfBits {
    static constexpr uint32_t value = IfThenElse<exp,SizeOfBits<N,exp+1>,(N / pow_two_with_exp<exp>::value) == 0>::value;
};


template <size_t A, typename B>
struct IfThenElse<A,B,true>{
    static constexpr size_t value = A;
};
template <size_t A, typename B>
struct IfThenElse<A,B,false>{
    static constexpr decltype(B::value) value = B::value;
};

这段代码的主要修改是使用了IfThenElse
这可以使在计算规模为<N,exp>的SizeOfBits::value时,只实例化一个分支(特化true或者特化false,模板的on demand实例化,见complete guide 1st edition chapter10)

此外,complete guide中还提及了一种归纳变量的方法,以使meta programm更像从递归改为迭代的设计:

EXAMPLE TWO

第一个是基模板定义,第二个是全特化,第三个是偏特化,第四个是全特化。
image

EXAMPLE THREE

#include <iostream>
#include <list>
#include <map>
#include <string>
#include <type_traits>
#include <vector>
using namespace std;

struct bracket_word;
struct word;

template <typename A, typename B, bool cond>
struct ifThenElse;

template <typename A, typename B>
struct ifThenElse<A, B, true> {
    static constexpr bool value = A::value;
};
template <typename A, typename B>
struct ifThenElse<A, B, false> {
    static constexpr bool value = B::value;
};

template <typename... TYPE_VAR>
struct isWord;

template <>
struct isWord<> : integral_constant<bool, true> {};

template <typename TYPE, typename... TYPE_VAR>
struct isWord<TYPE, TYPE_VAR...>
    : integral_constant<
          bool,
          is_same<TYPE, word>::value &&
              ifThenElse<isWord<TYPE_VAR...>, integral_constant<bool, true>,
                         (sizeof...(TYPE_VAR) > 0)>::value> {};

int main() {
    static_assert(isWord<>::value, "Expected true");
    static_assert(isWord<word>::value, "Expected true");
    static_assert(isWord<word, word>::value, "Expected true");
    static_assert(isWord<word, bracket_word>::value == false, "");
    static_assert(isWord<bracket_word>::value == false, "");
}
posted @ 2023-07-16 15:53  ijpq  阅读(10)  评论(0编辑  收藏  举报