Reputation: 5571
Can I use assert to enforce type definitions. Suppose there is a variable, double d
, how can you use assert
to assert that d is a double? If assert
is not applicable (which I am betting isn't), is there another option? I am specifically looking to test for implicit type casting during debugging, while benefiting from the functionality of assert
and #define NDEBUG
.
P.S Obviously I would want to use this for any type definition, just using double as an example here. The solution should be cross platform compatible and be compatible with C++03.
I like to add error checking to my class setters. For example, suppose there is a class, MyClass, with a private member variable, x:
void MyClass::setX(double input)
{
// assert x is double
x = input;
}
Upvotes: 6
Views: 11664
Reputation: 2616
You can create a template function, then overload the argument type for double
like this:
#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
}
That would give a run-time error. You can generate a compile time error by simply defining a function that takes a double reference:
void is_double(double&) { }
void MyClass::setX(double input)
{
is_double(x); // assert x is double
x = input;
}
Upvotes: 0
Reputation: 81349
Given the current definition of the code, a way to check at compile time whether both are of the same type is:
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;
}
Upvotes: 1
Reputation: 5571
You can use the ==
operator defined in the type_info
class to test for a specific type definition.
#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
}
Or borrowing from another SO answer using templates and 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;
}
}
Upvotes: 6
Reputation: 76519
You should be able to compare using std::is_same
and using decltype
. You can even use std::static_assert
to move the check to compile time. I've seen it happen in libc++ :)
Note these are C++11 features, so you'll need to have a compiler that supports decltype
Upvotes: 3
Reputation: 10720
It's really a compile time check, so you should use static asserts for this.
Here is an example using boost's static asserts and type traits.
#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>();
}
I assume you mean in terms of a template anyway.
Upvotes: 11