如何将一个写"若荟萃否则如果.."在C ++? [英] How would one write a "meta if else if.." in C++?

查看:182
本文介绍了如何将一个写"若荟萃否则如果.."在C ++?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚学C ++中的元编程基础知识,我认为这将是很好,看看下面的问题将由其他人来解决。此外,这将是非常不错的使用Boost元编程库看到一个解决方案,因为我认为他们是黑暗的角落我。所以,问题是,这可能会被改写更优雅?

假设我们有下面的结构:

 模板<的std ::为size_t大小>
结构type_factory
{
  的typedef typename的type_factory_impl<尺寸和GT; ::类型类型;
};

此结构应该是的typedef 键入,根据大小的值 type_factory_impl type_factory 的实施。用于确定算法键入是:

 如果(大小%位<无符号长长> ::值== 0)
  无符号的typedef long long类型;
否则,如果(大小%位<无符号长> ::值== 0)
  无符号的typedef长类型;
否则,如果(大小%位< unsigned int类型> ::值== 0)
  的typedef无符号整型类型;
否则,如果(大小%位<无符号短整数> ::值== 0)
  的typedef无符号短整型;
否则,如果(大小%位< unsigned char型> ::值== 0)
  无符号的typedef char类型;
其他
  static_assert(假的类型应该是多个无符号的字符大小);

我在两种方式解决了这个元程序。第一个是使用模式匹配直接,并使用元的if-else 第二个。考虑两种解决方案之间存在以下共同code:

 的#include< cstddef>
#包括LT&;&climits GT;的typedef unsigned char型UCHAR;
typedef的无符号短整数USINT;
的typedef无符号整型单元;
无符号的typedef ULONG长;
无符号的typedef长长ULONGLONG;//返回有多少Unsigned_Type位
模板< typename的Unsigned_Type>
结构位
{{枚举值= sizeof的(Unsigned_Type)* CHAR_BIT}; };//结构type_factory_impl ...模板<的std ::为size_t大小>
结构type_factory
{
  的typedef typename的type_factory_impl<尺寸和GT; ::类型类型;
};诠释的main()
{
  自动一个= type_factory&所述8是氢; ::类型(0); // 无符号字符
  经销商B = type_factory&所述16取代; ::类型(0); //无符号短整型
  汽车C = type_factory&下; 24每个::类型(0); // 无符号字符
  自动D = type_factory&所述32取代; ::类型(0); //无符号长
  汽车E = type_factory< 40 GT; ::类型(0); // 无符号字符
  汽车F = type_factory&下; 48> ::类型(0); //无符号短整型
  自动G = type_factory&下; 56> ::类型(0); // 无符号字符
  汽车H = type_factory&下; 64> ::类型(0); //无符号长长
}

第一个解决方案:

 模板<布尔is_uchar>
结构unsigned_char
{
  无符号的typedef char类型;
  static_assert(is_uchar,
     错误:大小必须是多个无符号的字符大小);
};
模板<>
结构unsigned_char<真>
{的typedef UCHAR类型; };模板<布尔is_usint,性病::为size_t大小>
结构unsigned_short_int
{的typedef typename的
   unsigned_char<大小%位<&UCHAR GT; ::值== 0> ::类型类型; };
模板<的std ::为size_t大小>
结构unsigned_short_int<真,大小>
{的typedef USINT类型; };模板<布尔is_uint,性病::为size_t大小>
结构unsigned_int
{的typedef typename的
   unsigned_short_int<大小%位<&USINT GT; ::值== 0,大小> ::类型类型; };
模板<的std ::为size_t大小>
结构unsigned_int<真,大小>
{typedef的UINT类型; };模板<布尔is_ulong,性病::为size_t大小>
结构unsigned_long
{的typedef typename的
   unsigned_int<大小%位< UINT> ::值== 0,大小> ::类型类型; };
模板<的std ::为size_t大小>
结构unsigned_long<真,大小>
{的typedef ULONG类型; };模板<布尔is_ulonglong,性病::为size_t大小>
结构unsigned_long_long
{的typedef typename的
   unsigned_long<大小%位< ULONG> ::值== 0,大小> ::类型类型; };
模板<的std ::为size_t大小>
结构unsigned_long_long<真,大小>
{的typedef ULONGLONG类型; };模板<的std ::为size_t大小>
结构type_factory_impl
{的typedef typename的
   unsigned_long_long<大小%位<&ULONGLONG GT; ::值== 0,大小> ::类型类型; };

第二个解决方案:

 模板< BOOL条件,类型名称之后,类型名否则>
IF结构
{的typedef否则类型; };
模板< typename的。然后,类型名否则>
结构IF<真,那么,否则>
{的typedef然后键入; };模板<的std ::为size_t大小>
结构type_factory_impl
{
  的typedef typename的
    IF<大小%位<&ULONGLONG GT; ::值== 0,ULONGLONG,
      类型名IF<大小%位< ULONG> ::值== 0,ULONG,
        类型名IF<大小%位< UINT> ::值== 0,UINT,
          TYPENAME IF<大小%位<&USINT GT; ::值== 0,USINT,
            TYPENAME IF<大小%位<&UCHAR GT; ::值== 0,UCHAR,UCHAR> ::类型
          > ::类型
        > ::类型
      > ::类型
    > ::类型类型;
};


解决方案

和你一样,我认为作为Boost.MPL黑魔法,所以我想这可能是试图用它来回答你的问题的场合。请记住,这是我与这个库是第一次尝试,而一些大师在那里可能会提供更好的解决方案。

的想法是使用升压:: MPL :: find_if 找到一个类型序列的第一个匹配的项目。

 的typedef的boost :: MPL ::矢量
    <
        无符号很长很长,
        无符号长,
        为unsigned int,
        无符号短,
        无符号字符
    > type_sequence;模板<的std ::为size_t大小>
结构predicate
{
    模板<类T>
    结构适用{
        静态常量布尔值=(大小%位< T> ::值== 0);
    };
};模板<的std ::为size_t大小>
结构type_factory_impl
{
    TYPENAME的typedef的boost :: MPL :: find_if
        <
            type_sequence,
            类型名称predicate<尺寸和GT; ::申请<提高:: MPL :: _ 1 GT;
        > ::类型iterator_type;    的typedef typename的提振:: MPL :: DEREF< iterator_type> ::类型类型;
};

这似乎给我很好的结果:

我不处理默认的情况下,但我的大脑刚开始通过我的鼻出血,我会尝试以后才能完成我的答案,并希望这会有所帮助。

I am just learning basics of metaprogramming in C++, and I thought it would be nice to see how the following question would be solved by others. Also, it would be very nice to see a solution using Boost metaprogramming libraries because I consider them as the dark corner for me. So the question is, could this be rewritten more elegantly?

Assume that we have the following struct:

template <std::size_t size>
struct type_factory
{
  typedef typename type_factory_impl<size>::type type;
};

This struct is supposed to typedef type, depending on the value of size. type_factory_impl is the implementation of type_factory. The algorithm that is used to determine type is:

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");

I have solved this metaprogram in two ways. The first one is using pattern matching directly, and the second one using meta if-else. Consider the following as common code between both solutions:

#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
}

The first solution:

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; };

The second solution:

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;
};

解决方案

Like you, I consider Boost.MPL as black magic, so I thought that could be the occasion to try and use it to answer your question. Please keep in mind that this is my very first attempt with this library, and that some guru out there will probably provide a better solution.

The idea is to use boost::mpl::find_if to find the first matching item in a sequence of types.

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;
};

It seems to give me the good result :

I'm not handling the "default" case, but my brain just started bleeding through my nose, I'll try to complete my answer later and hope this will help.

这篇关于如何将一个写&QUOT;若荟萃否则如果..&QUOT;在C ++?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆