I would like to make sure that a static_assert works as it should in a unit test. That is, if I have a
class MyClass {static_assert(my_type_trait<T>::value, "error"); };
then in the unit test MyClass<TypeWithTrait> myClass;
should 'pass' and MyClass<TypeWithoutTrait> myClass;
should 'fail'.
Is it possible to do something like this?
If you want to check that something fails to compile, you'll have to test that external to the code. Just write a simple file like:
#include "MyClass.h"
int main() {
MyClass<%T%> m;
}
And write a unit test that compiles that file with different values of %T%
. Verify that the compilation either succeeds as expected, or fails with something about static_assert
in the failure text as expected.
Barry's suggestion is one possibility, but if you have many things you want to test, you need to create many small files. What's more, those files could fail to compile for other reasons than what you expect, giving you a false sense your test passed.
An alternative is that instead of using static_assert
, you use some kind of SFINAE to detect whether or not something works. For traits classes this is a bit tricky, but you can do this:
template <class T>
using void_t = void;
template <class T>
struct foo;
template <>
struct foo <double> {};
template <class T, class = void>
struct has_foo_trait : std::false_type {};
template <class T>
struct has_foo_trait<T, void_t<decltype(foo<T>{})>> : std::true_type {};
int main(int, char**) {
std::cerr << has_foo_trait<int>::value;
std::cerr << has_foo_trait<double>::value;
return 0;
}
This prints out 01
. So now, instead of getting a hard failure from static_assert
ing directly, you can compute the value of the trait presence at compile time, and then static_assert
that you get the value you expect.
Note that the reason that traits classes are tricky is because the trait is declared as a general template, just not defined. So doing the "usual" metaprogramming thing of using the type directly inside the void_t
does not work. In order to trigger a soft SFINAE error in the true
branch of has_foo_trait
, I actually had to default construct an instance of the traits class. If you write your traits classes so they're not default constructible, this won't work. But in general you wouldn't write them that way. Would be curious to see if there's a better way to do it
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With