02小对象工具

如果需要保证类型T包含一个名为value的常量或名为type的类型,可以这样写:

template <typename T>
void myfunc()
{
typedef typename T::type ERROR_T_DOES_NOT_CONTAIN_type;
const int ASSERT_T_MUST_HAVE_STATIC_CONSTANT_value(T::value);
};

那么如果传进来的T没有value或没有type,就会报错。

复杂的断言通过不完整类型不能构造,或者如果T是不完整类型,sizeof(T)导致编译错误来实现。

布尔断言

template <bool STATEMENT>
struct static_assertion
{};
template <>
struct static_assertion<false>;

对false的特化没有实现,如果传入一个false值,将会报一个编译期错误。

用宏封装一下:

#define MXT_ASSERT(statement) sizeof(static_assertion<(statement)>)

宏的问题是逗号:

MXT_ASSERT(is_well_defined< std::map<int, double> >::value);

int的逗号前面的部分会识别为宏的第一个参数,后面的部分会识别为宏的第二个参数。

解决方法1:用typedef

typedef std::map<int, double> map_type;
MXT_ASSERT( is_well_defined<map_type>::value );

解决方法2:加括号

MXT_ASSERT(( is_well_defined< std::map<int, double> >::value ));

static_assertion可以继承:

template <typename T>
class small_object_allocator : static_assertion<(sizeof(T)<64)>
{};

因为static_assertion是一个类模板嘛。

断言合法性

如果要检查一些表达式的有效性,并且返回非void:

#define MXT_ASSERT_LEGAL(statement) sizeof(statement)

如果允许返回void:

#define MXT_ASSERT_LEGAL(statement) sizeof((statement), 0)//因为void是不完整类型

如果要检查T是否有一个函数empty:

template <typename T>
void do_something(T& x)
{
    MXT_ASSERT_LEGAL(static_cast<bool>(x.empty()));
    if (x.empty())
    {
        // ...
    }
}

其他的应用包括:

#define MXT_CONST_REF_TO(T) (*static_cast<const T*>(0))/**验证解const引用合法,
                                                    static_cast<const T*>(0)得到一个const T*,
                                                    *static_cast<const T*>(0)是解引用,下面同理*/

#define MXT_REF_TO(T) (*static_cast<T*>(0))//验证解引用合法
template <typename obj_t, typename iter_t>
class assert_iterator
{
    enum
    {
    verify_construction =
    MXT_ASSERT_LEGAL(obj_t(*MXT_CONST_REF_TO(iter_t))),	/**验证拷贝构造函数合法
							MXT_CONST_REF_TO(iter_t)得到一个iter_t对象,
                                                        *MXT_CONST_REF_TO(iter_t)得到一个obj_t对象,
							obj_t(*MXT_CONST_REF_TO(iter_t))就是拷贝构造,下面同理*/
	verify_assignment =
	MXT_ASSERT_LEGAL(MXT_REF_TO(obj_t) = *MXT_CONST_REF_TO(iter_t)),//验证赋值操作符合法
	verify_preincr =
	MXT_ASSERT_LEGAL(++MXT_REF_TO(iter_t)),//验证前置自增合法
	verify_postincr =
	MXT_ASSERT_LEGAL(MXT_REF_TO(iter_t)++)//验证后置自增合法
	};
};

用函数指针建模concept

template <typename T1, typename T2>
struct static_assert_can_copy_T1_to_T2
{
static void concept_check(T1 x, T2 y)
{
T2 z(x); // T2 must be constructable from T1
y = x; // T2 must be assignable from T1
}
static_assert_can_copy_T1_to_T2()
{
void (*f)(T1, T2) = concept_check;
}
};

通过派生或生成实例来使用

template <typename T>
T sqrt(T x)
{
static_assert_can_copy_T1_to_T2<T, double> CHECK1;
}
template <typename T>
class math_operations : static_assert_can_copy_T1_to_T2<T, double>
{};

这里解释一下。当生成CHECK1对象的时候,就会调用static_assert_can_copy_T1_to_T2的构造函数。类模板的成员函数在用到的时候才会生成对应的代码,构造函数里用到concept_check,所以生成concept_check的代码,并且检查T2 z(x);y=x;的合法性。

标签技术

在标准库的例子如iterator。标签的好处是构建临时标签对象代价很小,并且只编译需要的功能。

类型标签

struct naive_algorithm_tag {};
struct precise_algorithm_tag {};
template <typename T>
inline T log1p(T x, naive_algorithm_tag);
template <typename T>
inline T log1p(T x, precise_algorithm_tag);

也可以是模板标签:

template <int N>
struct algorithm_precision_level {};
template <typename T, int N>
inline T log1p(T x, algorithm_precision_level<N>);
// ...
double x = log1p(3.14, algorithm_precision_level<4>());

函数标签

enum algorithm_tag_t
{
NAIVE,
PRECISE
};
inline static_value<algorithm_tag_t, NAIVE> naive_algorithm_tag()
{
    return 0; 
}
inline static_value<algorithm_tag_t, PRECISE> precise_algorithm_tag()
{
    return 0;
}

标签是函数指针,好处是可以为相同的运行时和编译时算法提供统一的语法。但感觉很少写运行时+编译时两套实现,暂时跳过。

标签迭代

用0填充数组:

template <typename T, int N>
void zeroize_helper(T* const data, static_value<int, N>)
{
zeroize_helper(data, static_value<int, N-1>());
data[N-1] = T();
}
template <typename T>
void zeroize_helper(T* const data, static_value<int, 1>)
{
data[0] = T();
}
template <typename T, int N>
void zeroize(T (&data)[N])
{
zeroize_helper(data, static_value<int, N>());
}

或者可以调换一下语句的顺序:

template <typename T, int N>
void zeroize_helper(T* const data, static_value<int, N>)
{
data[N-1] = T();
zeroize_helper(data, static_value<int, N-1>());
}

这是线性的,也可以以指数的形式,假设N是2的幂:

template <int N, int M>
struct index
{
};
template <typename T, int N, int M>
void zeroize_helper(T* const data, index<N, M>)
{
zeroize_helper(data, index<N/2, M>());
zeroize_helper(data, index<N/2, M+N/2>());
}
template <typename T, int M>
void zeroize_helper(T* const data, index<1, M>)
{
data[M] = T();
}
template <typename T, int N>
void zeroize(T (&data)[N])
{
zeroize_helper(data, index<N, 0>());
}
double test[8];
zeroize(test);

展开如下:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统中管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确性。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值