meta program - 实例化

发布时间 2023-07-16 15:57:33作者: ijpq
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更像从递归改为迭代的设计: