C++11 模板元编程 - 测试断言

2016-09-16  本文已影响559人  MagicBowen

测试最重要的是要有断言。C++标准支持的编译期断言只有一个:static_assert

static_assert是C++11标准引入的一个新关键字,用于在编译期做静态断言。它需要两个参数,第一个是一个可以在编译期返回bool值的常量表达式,第二个是一个字符串常量,用于当断言失败时编译器输出用。

static_assert(sizeof(int) < 1, "Invoke an assertion failure!");

当编译器编译到如上代码时会产生一个编译错误,在错误报告中会包含字符串“Invoke an assertion failure!”。

在前面的介绍中,我们已经将模板元编程的计算对象和返回结果都统一成类型了,所以我们需要对static_assert进行封装,让其能够直接对类型进行断言。

首先我们需要一个断言ASSERT_TRUE(),它可以针对返回BoolType的元编程表达式进行断言。例如可以如下使用:

ASSERT_TRUE(__bool(true));
ASSERT_TRUE(__not(__false()));
ASSERT_FALSE(__or(__true(), __false()));

我们需要用static_assert实现ASSERT_TRUE,就需要对ASSERT_TRUE的入参调用__value()元函数求值。如下是ASSERT_TRUE的实现:

// "tlp/test/details/Asserter.h"

#define ASSERT_TRUE(T)                  \
static_assert(__value(T), "Assert Failed: expect "#T" be true, but be false!")

同样我们实现ASSERT_FALSE如下:

// "tlp/test/details/Asserter.h"

#define ASSERT_FALSE(T)                 \
static_assert(!(__value(T)), "Assert Failed: expect "#T" be false, but be true!")

接下来我们实现用于断言两个类型是否相等的ASSERT_EQ()ASSERT_NE()

// "tlp/test/details/Asserter.h"

#define ASSERT_EQ(T, Expected)          \
static_assert(__value(__is_eq(T, Expected)), "Assert Failed: expect "#T" be equal to "#Expected"!")

#define ASSERT_NE(T, Expected)          \
static_assert(!(__value(__is_eq(T, Expected))), "Assert Failed: expect "#T" be not equal to "#Expected"!")

它们的用法如下:

ASSERT_EQ(__int(0), __int(0));
ASSERT_NE(__int(0), __int(1));
ASSERT_EQ(__if(__true(), int, char), int);
ASSERT_EQ(__if(__false(), int, char), char);

TLP库中有一个特殊的类型NullType,它的定义如下:

// "tlp/base/NullType.h"

struct NullType;

#define __null() NullType

NullType仅有类声明,所以不能实例化。NullType被TLP库用于各种计算返回的无效值中。对此有一个元函数__valid()专门用于判断表达式的值是否为NullType。

template<typename T>
struct Valid
{
    using Result = __true();
};

template<>
struct Valid<NullType>
{
    using Result = __false();
};

#define __valid(...)    typename Valid<__VA_ARGS__>::Result

当然你也可以对其扩展,通过定义Valid的不同特化,来支持更多的错误类型。

对此,TLP提供了断言ASSERT_VALIDASSERT_INVALID,专门用于判断表达式是否有效:

// "tlp/test/details/Asserter.h"

#define ASSERT_VALID(T)                 \
static_assert(__value(__valid(T)), "Assert Failed: expect "#T" be valid, but be invalid!")

#define ASSERT_INVALID(T)               \
static_assert(!(__value(__valid(T))), "Assert Failed: expect "#T" be invalid, but be valid!")

测试用例

返回 C++11模板元编程 - 目录

上一篇下一篇

猜你喜欢

热点阅读