单元测试:检查是否不应编译某些表达式
Unit test: checks that some expressions shouldn't be compiled
在我想检查的单元测试中,某些表达式无法编译。例如,如果我正在编写非复制类,我想检查无法调用复制构造函数(因此,不应编译copy构造函数的表达式)。目前,我正在使用Google测试,这没有这种可能性。
众所周知,可以使用Sfinae来制作。基本思想是,应该测试的表达应将其传递给decltype()作为参数。表达的某些部分必须是模板(不使用模板参数编译器立即指向错误)。现在,如果可以编译表达式,则可以确定表达式的类型,并选择特定的模板(其中写入contuments neclype)。如果无法编译表达式,则将选择其他模板。后来,在运行时,我们可以分析结果...
该方法的主要缺点是表达式应该是模板参数,这会导致不良的代码可读性。我要问的问题:在哪里写整个表达式的方法,而不将其拆分为模板参数和表达式本身?还有另一个问题,有可能避免使用std :: dectval?
例如,目前我应该写:
COMPILE_TEST(..., T, noncopyable, T(std::declval<T>()));
如果不需要模板参数,我可以写:
COMPILE_TEST(..., noncopyable(std::declval<noncopyable>()));
,在理想的情况下,我想写的东西,这是:
COMPILE_TEST(..., { noncopyable t; noncopyable t2(t); });
但我想这是完全不可能的。
完整示例(https://coliru.stacked-crooked.com/a/ecbc42e7596bc4dc):
#include <stdio.h>
#include <utility>
#include <vector>
template <typename...> using _can_compile = void;
struct cant_compile { constexpr static bool value = false; };
#if COMPILE_TEST_ASSERTS
#define CAN_COMPILE_ASSERT(val, name, param, decl, ...)
static_assert(val, "this shoul'd not be compiled (" #name "): " __VA_ARGS__ " [with " #param "=" #decl "]");
#else
#define CAN_COMPILE_ASSERT(name, param, decl, ...) static_assert(true, "")
#endif
#define COMPILE_TEST(name, param, decl, ...)
template <typename T, typename = void> struct can_compile_##name : public cant_compile {};
template <typename T> struct can_compile_##name<T, _can_compile<decltype(__VA_ARGS__)>> { constexpr static bool value = true; };
CAN_COMPILE_ASSERT(!can_compile_##name<decl>::value, name, param, decl, #__VA_ARGS__);
constexpr bool name = can_compile_##name<decl>::value;
struct noncopyable_good
{
noncopyable_good() {}
noncopyable_good(const noncopyable_good&) = delete;
};
struct noncopyable_bad
{
noncopyable_bad() {}
// noncopyable_bad(const noncopyable_bad&) = delete;
};
COMPILE_TEST(good, T, noncopyable_good, T(std::declval<T>()));
COMPILE_TEST(bad, T, noncopyable_bad, T(std::declval<T>()));
int main()
{
printf("noncopyable_good can%s be copiedn", good ? "" : "'t");
printf("noncopyable_bad can%s be copiedn", bad ? "" : "'t");
return 0;
}
类似的问题:
- 是否可以使用gtest assert_does_not_compile?
- 断言代码不编译
- 静态断言和sfinae
- 为什么此Sfinae摘要在G 中不起作用,而是在MSVC中工作?
这是对您的代码的非常轻微的修改,可以消除额外的参数。
template <class X, class Y>
auto my_declval() -> Y;
#define MY_DECLVAL(...) my_declval<T, __VA_ARGS__>()
template <typename...> using _can_compile = void;
struct cant_compile { constexpr static bool value = false; };
#if COMPILE_TEST_ASSERTS
#define CAN_COMPILE_ASSERT(val, name, decl)
static_assert(val, "this shoul'd not be compiled (" #name "): " #decl );
#else
#define CAN_COMPILE_ASSERT(name, decl, ...) static_assert(true, "")
#endif
#define COMPILE_TEST(name, ...)
template <typename T, typename = void> struct can_compile_##name : public cant_compile {};
template <typename T> struct can_compile_##name<T, _can_compile<decltype(__VA_ARGS__)>> { constexpr static bool value = true; };
CAN_COMPILE_ASSERT(can_compile_##name<void>::value, name, #__VA_ARGS__);
constexpr bool name = can_compile_##name<void>::value;
struct noncopyable_good
{
noncopyable_good() {}
noncopyable_good(const noncopyable_good&) = delete;
};
struct noncopyable_bad
{
noncopyable_bad() {}
// noncopyable_bad(const noncopyable_bad&) = delete;
};
COMPILE_TEST(good, noncopyable_good(MY_DECLVAL(noncopyable_good)));
COMPILE_TEST(bad, noncopyable_bad(MY_DECLVAL(noncopyable_bad)));
实时演示
想法是,您需要检查的表达式必须取决于模板参数,但是模板参数不必连接到您需要检查的类型。因此,my_declval是为了置换的,取决于某些虚拟参数 T
,而传递的实际参数为 void
(可能是任何类型)。
(我删除了CAN_COMPILE_ASSERT
调用中的否定,因为我认为它是错误的,并简化了其定义)。
您需要在要检查的表达式中至少具有一个my_declval。
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- 即使使用调试编译标志,表达式也是"optimized out"
- 编译 llvm 3.1 时,为什么会出现错误:在">"标记之前预期主表达式
- C++ 编译错误:意外的类型名称"字符串":预期的表达式
- 如何在常量计算表达式中获取编译时错误?
- 不是 VS2017 中的编译时常量表达式
- C++编译错误(有符号和无符号整数表达式之间的比较)
- 将编译时定义大小的数组初始化为常量表达式
- 用MASM编译汇编文件时,缺少表达式操作员
- 如何判断表达式是在编译时还是运行时计算的?
- 基于用户表达式在编译时参数化函数
- 是否可以表示不应编译的表达式的静态_assert
- 使用折叠表达式初始化静态 constexpr 类数据成员不编译
- 当使用无效表达式时,概念是否应该无法编译?
- 单元测试:检查是否不应编译某些表达式
- 减少 std::正则表达式编译时间 C++
- 使用提升正则表达式C++进行编译
- 使用表达式模板编译时间数组索引--constexpr