Можете ли вы использовать assert для тестирования определений типов в C ++? - PullRequest
3 голосов
/ 26 сентября 2011

Могу ли я использовать assert для обеспечения определения типов.Предположим, есть переменная double d, как вы можете использовать assert, чтобы утверждать, что d является двойным?Если assert не применимо (на что я держу пари), есть ли другой вариант?Я специально ищу тест на неявное приведение типов во время отладки, получая выгоду от функциональности assert и #define NDEBUG.

PS Очевидно, я хотел бы использовать это для любого определения типа, просто используя здесь в качестве примера double.Решение должно быть кроссплатформенным и совместимым с C ++ 03.

Мне нравится добавлять проверку ошибок в мои установщики классов.Например, предположим, что существует класс MyClass с закрытой переменной-членом x:

void MyClass::setX(double input)
{
   // assert x is double
   x = input;
}

Ответы [ 5 ]

7 голосов
/ 26 сентября 2011

Это действительно проверка времени компиляции, поэтому вы должны использовать статические утверждения для этого.

Вот пример использования статических утверждений и черт типа 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>();
}

Я предполагаю, что вы имеете в видув любом случае с точки зрения шаблона.

3 голосов
/ 26 сентября 2011

Вы можете использовать оператор ==, определенный в type_info классе , для проверки определения определенного типа.

#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
}

Или заимствование у другого SO ответа с использованием шаблонов и try / catch:

#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;
    }
}
1 голос
/ 26 сентября 2011

Учитывая текущее определение кода, во время компиляции можно проверить, являются ли оба типа одинаковыми:

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;
}
1 голос
/ 26 сентября 2011

Вы можете сравнивать, используя std::is_same и decltype. Вы даже можете использовать std::static_assert для перемещения чека во время компиляции. Я видел это в libc ++:)

Обратите внимание, что это функции C ++ 11, поэтому вам понадобится компилятор, поддерживающий decltype

0 голосов
/ 27 сентября 2011

Вы можете создать шаблонную функцию, а затем перегрузить тип аргумента для 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;
}
...