我只是在学习C ++中元编程的基础知识,我认为看看其他人如何解决以下问题会很高兴。另外,看到使用Boost元编程库的解决方案会非常好,因为我认为它们对我来说是一个黑暗的角落。所以问题是,这可以更优雅地重写吗?
假设我们有以下结构:
template <std::size_t size>
struct type_factory
{
typedef typename type_factory_impl<size>::type type;
};
此结构应该typedef
type
,具体取决于size
的值。 type_factory_impl
是type_factory
的实施。用于确定type
的算法是:
if(size % bits<unsigned long long>::value == 0)
typedef unsigned long long type;
else if(size % bits<unsigned long>::value == 0)
typedef unsigned long type;
else if(size % bits<unsigned int>::value == 0)
typedef unsigned int type;
else if(size % bits<unsigned short int>::value == 0)
typedef unsigned short int type;
else if(size % bits<unsigned char>::value == 0)
typedef unsigned char type;
else
static_assert(false, "The type should be multiple of 'unsigned char' size");
我已经用两种方式解决了这个元程序。第一个是直接使用模式匹配,第二个使用meta if-else
。请考虑以下两种解决方案之间的通用代码:
#include <cstddef>
#include <climits>
typedef unsigned char uchar;
typedef unsigned short int usint;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long ulonglong;
// Returns how many bits in Unsigned_Type
template <typename Unsigned_Type>
struct bits
{ enum { value = sizeof(Unsigned_Type)*CHAR_BIT }; };
// struct type_factory_impl ...
template <std::size_t size>
struct type_factory
{
typedef typename type_factory_impl<size>::type type;
};
int main()
{
auto a = type_factory<8>::type(0); // unsigned char
auto b = type_factory<16>::type(0); // unsigned short int
auto c = type_factory<24>::type(0); // unsigned char
auto d = type_factory<32>::type(0); // unsigned long
auto e = type_factory<40>::type(0); // unsigned char
auto f = type_factory<48>::type(0); // unsigned short int
auto g = type_factory<56>::type(0); // unsigned char
auto h = type_factory<64>::type(0); // unsigned long long
}
template <bool is_uchar>
struct unsigned_char
{
typedef unsigned char type;
static_assert(is_uchar,
"error: size must be multiple of 'unsigned char' size");
};
template <>
struct unsigned_char <true>
{ typedef uchar type; };
template <bool is_usint, std::size_t size>
struct unsigned_short_int
{ typedef typename
unsigned_char<size % bits<uchar>::value == 0>::type type; };
template <std::size_t size>
struct unsigned_short_int <true, size>
{ typedef usint type; };
template <bool is_uint, std::size_t size>
struct unsigned_int
{ typedef typename
unsigned_short_int<size % bits<usint>::value == 0, size>::type type; };
template <std::size_t size>
struct unsigned_int <true, size>
{ typedef uint type; };
template <bool is_ulong, std::size_t size>
struct unsigned_long
{ typedef typename
unsigned_int<size % bits<uint>::value == 0, size>::type type; };
template <std::size_t size>
struct unsigned_long <true, size>
{ typedef ulong type; };
template <bool is_ulonglong, std::size_t size>
struct unsigned_long_long
{ typedef typename
unsigned_long<size % bits<ulong>::value == 0, size>::type type; };
template <std::size_t size>
struct unsigned_long_long <true, size>
{ typedef ulonglong type; };
template <std::size_t size>
struct type_factory_impl
{ typedef typename
unsigned_long_long<size % bits<ulonglong>::value == 0, size>::type type; };
template <bool condition, typename Then, typename Else>
struct IF
{ typedef Else type; };
template <typename Then, typename Else>
struct IF <true, Then, Else>
{ typedef Then type; };
template <std::size_t size>
struct type_factory_impl
{
typedef typename
IF<size % bits<ulonglong>::value == 0, ulonglong,
typename IF<size % bits<ulong>::value == 0, ulong,
typename IF<size % bits<uint>::value == 0, uint,
typename IF<size % bits<usint>::value == 0, usint,
typename IF<size % bits<uchar>::value == 0, uchar, uchar>::type
>::type
>::type
>::type
>::type type;
};
答案 0 :(得分:4)
和你一样,我认为Boost.MPL是黑魔法,所以我认为可以尝试用它来回答你的问题。请记住,这是我对这个库的第一次尝试,那里的一些大师可能会提供更好的解决方案。
我们的想法是使用boost::mpl::find_if来查找类型序列中的第一个匹配项。
typedef boost::mpl::vector
<
unsigned long long,
unsigned long,
unsigned int,
unsigned short,
unsigned char
> type_sequence;
template<std::size_t size>
struct predicate
{
template<class T>
struct apply {
static const bool value = (size % bits<T>::value == 0);
};
};
template<std::size_t size>
struct type_factory_impl
{
typedef typename boost::mpl::find_if
<
type_sequence,
typename predicate<size>::apply<boost::mpl::_1>
>::type iterator_type;
typedef typename boost::mpl::deref<iterator_type>::type type;
};
这似乎给了我很好的结果:
我没有处理“默认”情况,但是我的大脑刚开始流鼻血,我会稍后尝试完成我的答案并希望这会有所帮助。
答案 1 :(得分:4)
专业化有问题吗?
template<size_t N>
struct lowest_bit
{
enum
{
lowest_bit_removed = N & (N-1),
value = N ^ lowest_bit_removed
};
};
template<size_t size> struct type_factory_impl { typedef uchar type; };
template<> struct type_factory_impl<sizeof(ushort) *CHAR_BIT> { typedef ushort type; };
template<> struct type_factory_impl<sizeof(uint) *CHAR_BIT> { typedef uint type; };
template<> struct type_factory_impl<sizeof(ulong) *CHAR_BIT> { typedef ulong type; };
template<> struct type_factory_impl<sizeof(ulonglong)*CHAR_BIT> { typedef ulonglong type; };
template<size_t size>
struct type_factory
{
typedef typename type_factory_impl<lowest_bit<size>::value>::type type;
};