您可以使用 assert 来测试 C++ 中的类型定义吗?

Posted

技术标签:

【中文标题】您可以使用 assert 来测试 C++ 中的类型定义吗?【英文标题】:Can you use assert to test type defintions in C++? 【发布时间】:2011-09-26 18:58:26 【问题描述】:

我可以使用assert 来强制执行类型定义吗?假设有一个变量double d,你怎么能用assert断言d是一个double呢?如果assert 不适用(我打赌不适用),还有其他选择吗?我特别希望在调试期间测试隐式类型转换,同时受益于assert#define NDEBUG 的功能。

附言 显然,我想将它用于任何类型定义,这里仅使用 double 作为示例。解决方案应该是跨平台兼容的,并且兼容C++03。

我喜欢在我的类设置器中添加错误检查。例如,假设有一个类 MyClass,它有一个私有成员变量 x:

void MyClass::setX(double input)

   // assert x is double
   x = input;

【问题讨论】:

assert() 用于运行时检查。对于数据类型,您可以使用更强大的工具 - 编译时检查。描述一个具体的场景,也许 SO 集体会想办法把它变成编译错误的情况。 无论在哪里定义x,都将类型设为double @Gman,我喜欢在设置器中添加错误检查以确保稳健性。 我是 C++ 新手,你能告诉我在什么情况下 double 声明的参数可能是别的东西?谢谢 @NiklasR:他似乎想要断言 member 是否是别的东西。无法想象那会是怎样。 【参考方案1】:

这实际上是一个编译时检查,所以你应该为此使用静态断言。

这是一个使用 boost 的静态断言和类型特征的示例。

#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>

template<typename T>
  void some_func() 
    BOOST_STATIC_ASSERT( (boost::is_same<double, T>::value) );
  

TEST(type_check) 
  some_func<double>();

我假设你的意思是模板。

【讨论】:

那是BOOST_STATIC_ASSERT,它可能需要双括号,因为参数有一个逗号。 @K-ballo 你说得对,先生,我已经纠正了。想象一下我的耻辱。【参考方案2】:

您可以使用type_info class 中定义的== 运算符来测试特定类型定义。

#include <assert.h>
#include <iostream>
#include <typeinfo>

int main ()

    double a = 0;

    std::cout << typeid(a).name() << std::endl;

    assert(typeid(a)==typeid(double));
    assert(typeid(a)==typeid(int)); // FAIL

或者使用模板和 try/catch 从另一个 SO answer 借用:

#include <assert.h>
#include <iostream>
#include <typeinfo>

template <typename X, typename A>
inline void Assert(A assertion)

    if( !assertion ) throw X();


#ifdef NDEBUG
    const bool CHECK_ASSERT = false;
#else
    const bool CHECK_ASSERT = true;
#endif

struct Wrong  ;

int main ()

    double a = 0;

    std::cout << typeid(a).name() << std::endl;

    assert(typeid(a)==typeid(double));
    Assert<Wrong>(!CHECK_ASSERT || typeid(a)==typeid(double));
    try
    
    //assert(typeid(a)==typeid(int)); // FAIL and Abort()
        Assert<Wrong>(!CHECK_ASSERT || typeid(a)==typeid(int)); // FALL
    
    catch (Wrong)
    
        std::cerr <<"Exception, not an int" <<std::endl;
    

【讨论】:

【参考方案3】:

您应该能够使用std::is_samedecltype 进行比较。您甚至可以使用std::static_assert 将检查移动到编译时间。我已经看到它发生在 libc++ 中:)

请注意,这些是 C++11 功能,因此您需要有一个支持 decltype 的编译器

【讨论】:

应该是std::is_same,注意基于 C++03 的解决方案仍然是可能的,但是问题中没有足够的上下文信息来提出这样的建议。在 C++11 世界中,static_assert 也更适合一次。 @K-ballo C++03 还需要什么其他上下文?【参考方案4】:

鉴于代码的当前定义,在编译时检查两者是否属于同一类型的方法是:

template< typename T, typename U >
void assert_same_type( T const&, U const& )

     int error[ sizeof( T ) ? -1 : -2 ]; // error array of negative size, dependent on T otherwise some implementations may cause an early error message even when they shouldn't


template< typename T >
void assert_same_type( T&, T& )

void MyClass::setX(double input)

   assert_same_type( x, input ); // If the fallback case is instantiated then a compile time error will arise of trying to declare an array of negative size.

   x = input;

【讨论】:

@rubenvb:我不确定是否真的是这样,但如果只是在后备案例中添加一个错误。我会更新我的答案。【参考方案5】:

您可以创建一个模板函数,然后像这样重载double 的参数类型:

#include <cassert>

template<class T>
bool is_double(T)  return false; 
bool is_double(double)  return true; 

int main() 
    int i = 1;
    double d = 3.14;
    assert( is_double(d) );
    assert( is_double(i) ); // fails

这会产生运行时错误。您可以通过简单地定义一个采用双重引用的函数来生成编译时错误:

void is_double(double&)  

void MyClass::setX(double input)

  is_double(x); // assert x is double
  x = input;

【讨论】:

以上是关于您可以使用 assert 来测试 C++ 中的类型定义吗?的主要内容,如果未能解决你的问题,请参考以下文章

关于c++中的assert语句

pytest文档11-assert断言

C语言C++中assert的用法

C++中的assert

Swift:Assert 语句中的可选元组类型

单元测试