单元测试:检查是否不应编译某些表达式

Unit test: checks that some expressions shouldn't be compiled

本文关键字:编译 表达式 检查 是否 单元测试      更新时间:2023-10-16

在我想检查的单元测试中,某些表达式无法编译。例如,如果我正在编写非复制类,我想检查无法调用复制构造函数(因此,不应编译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。