你可以尝试这样做。UpToN类型在此处作为模板参数,但您可以将其更改为size_t。我这样做是因为unsigned long long可能比size_t更大。为了简单起见,此版本仅生成无符号类型。
此元编程迭代通过无符号整数类型列表,将upto_n转换为候选类型(Try_t),然后再次转换为upto_n的类型(Max_t),并检查它是否与原始upto_n相等。
如果强制转换保留此等式并且Try_t的大小小于或等于Best_t的大小,则使用Try_t替换Best_t继续迭代。
unsigned char特殊化通过候选类型终止迭代。
#include <iostream>
template <typename T> struct next_t {};
template <> struct next_t<unsigned long long> { typedef unsigned long type; };
template <> struct next_t<unsigned long> { typedef unsigned int type; };
template <> struct next_t<unsigned int> { typedef unsigned short type; };
template <> struct next_t<unsigned short> { typedef unsigned char type; };
template <typename Max_t, Max_t upto_n, typename Best_t=Max_t, typename Try_t=unsigned long long, bool try_is_better = (sizeof(Try_t) <= sizeof(Best_t) && upto_n == Max_t(Try_t(upto_n)))>
struct tight_int {
typedef typename tight_int<Max_t, upto_n, Best_t, typename next_t<Try_t>::type>::type type;
};
template <typename Max_t, Max_t upto_n, typename Best_t, typename Try_t>
struct tight_int<Max_t, upto_n, Best_t, Try_t, true> {
typedef typename tight_int<Max_t, upto_n, Try_t, typename next_t<Try_t>::type>::type type;
};
template <typename Max_t, Max_t upto_n, typename Best_t>
struct tight_int<Max_t, upto_n, Best_t, unsigned char, true> {
typedef unsigned char type;
};
template <typename Max_t, Max_t upto_n, typename Best_t>
struct tight_int<Max_t, upto_n, Best_t, unsigned char, false> {
typedef Best_t type;
};
int main() {
typedef tight_int<size_t, 255>::type tight_255_t;
typedef tight_int<size_t, 256>::type tight_256_t;
typedef tight_int<size_t, 65535>::type tight_65535_t;
typedef tight_int<size_t, 65536>::type tight_65536_t;
std::cout << "255 : " << sizeof(tight_255_t) << std::endl;
std::cout << "256 : " << sizeof(tight_256_t) << std::endl;
std::cout << "65535 : " << sizeof(tight_65535_t) << std::endl;
std::cout << "65536 : " << sizeof(tight_65536_t) << std::endl;
}
这段代码使用辅助类next_t来减少tight_int的特化次数。但是,如果计算默认定义,则tight_int仍有4个特化()。
我们可以通过引入一个辅助类来选择基于布尔参数try_is_better的类型Try_t和Best_t之间的类型,从而将特化计数减半。结果传递给下一次迭代的Best_t。这种改变将使我们保留最少的特化计数:默认定义(处理所有未特化的类型)和一个处理unsigned char的迭代终止特化。不幸的是,这种优化会影响可读性,并且往往会掩盖元编程的底层机制。
对于以下版本,新的辅助类type_sel替换了try_is_better为true和false的tight_int的特化。您可能会注意到,模板参数列表语法确实开始失去控制:
template <typename T> struct next_t {};
template <> struct next_t<unsigned long long> { typedef unsigned long type; };
template <> struct next_t<unsigned long> { typedef unsigned int type; };
template <> struct next_t<unsigned int> { typedef unsigned short type; };
template <> struct next_t<unsigned short> { typedef unsigned char type; };
// helper class type_sel which selects one of two types based on a static bool
template <bool, typename True_t, typename False_t>
struct type_sel { typedef True_t type; };
template <typename True_t, typename False_t>
struct type_sel<false, True_t, False_t> { typedef False_t type; };
// default definition of tight_int, handling all Try_t except unsigned char
template <typename Max_t, Max_t upto_n, typename Best_t = Max_t,
typename Try_t = unsigned long long,
bool try_is_better=(sizeof(Try_t)<=sizeof(Best_t) && upto_n==Max_t(Try_t(upto_n)))>
struct tight_int {
typedef typename tight_int<Max_t, upto_n,
typename type_sel<try_is_better, Try_t, Best_t>::type,
typename next_t<Try_t>::type>::type type;
};
// unsigned char specialization of tight_int terminates iteration through types
template <typename Max_t, Max_t upto_n, typename Best_t, bool try_is_better>
struct tight_int<Max_t, upto_n, Best_t, unsigned char, try_is_better> {
typedef typename type_sel<try_is_better, unsigned char, Best_t>::type type;
};
我仍然不喜欢类型列表的实现方式(作为next_t)。我不喜欢每个类型都需要两次指定:一次作为特化的模板参数,一次作为next_type::type。相反,我们可以使用一个嵌套自身以形成类型列表的类。下面,Try_t被Trylist_t替换。新的辅助类tpair嵌套在模板类型参数中,以形成迭代的类型列表。现在可以用单行代码定义类型列表:
tpair<unsigned long long, tpair<unsigned long, tpair<unsigned int, ... > >
这种类型列表类可以在其他地方用于构建其他类型的列表。(请记住,我们被绑定到C++03规范,因此不支持变参模板参数列表。)
以下是带有tpair类型列表的下一个版本。我没有在模板参数列表中添加换行符,因为现在它已经无法阅读了。
template <typename My_t, typename Next_t=void>
struct tpair { typedef My_t type; typedef Next_t next_tpair; } ;
template <bool, typename True_t, typename False_t>
struct type_sel { typedef True_t type; };
template <typename True_t, typename False_t>
struct type_sel<false, True_t, False_t> { typedef False_t type; };
template <typename Max_t, Max_t upto_n, typename Best_t = Max_t, typename Trylist_t = tpair<unsigned long long, tpair<unsigned long, tpair<unsigned int, tpair<unsigned short, tpair<unsigned char> > > > >, bool try_is_better=(sizeof(Trylist_t::type)<=sizeof(Best_t) && upto_n==Max_t((typename Trylist_t::type) upto_n))>
struct tight_int {
typedef typename tight_int<Max_t, upto_n, typename type_sel<try_is_better, typename Trylist_t::type, Best_t>::type, typename Trylist_t::next_tpair>::type type;
};
template <typename Max_t, Max_t upto_n, typename Best_t, bool try_is_better>
struct tight_int<Max_t, upto_n, Best_t, typename tpair<unsigned char>, try_is_better> {
typedef typename type_sel<try_is_better, unsigned char, Best_t>::type type;
};
std::conditional
版本,结合<climits>
中适当的宏。请注意,uint8_t
等是 C++11 的内容,因为 C++03 使用的是 C89 标准库。 - T.C.