【问题标题】:Can you use assert to test type defintions in C++?您可以使用 assert 来测试 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 是否是别的东西。无法想象那会是怎样。

标签: c++ debugging casting assert


【解决方案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;
    }
    

    【讨论】:

      猜你喜欢
      • 2013-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-02
      相关资源
      最近更新 更多