How to expect static_assert to crash and work with it using the Boost.Test framework?

If I have a method that takes a template parameter that needs to be converted to base_of or the same type as the return type, how can I do this?

For example, consider this method:

template <class T> class IFoo { public: template <class ServiceT> T* as() { static_assert(std::is_same< T, ServiceT >::value || std::is_convertible< T, ServiceT >::value || std::is_base_of< ServiceT, T >::value, "IFoo< T >::as< ServiceT >() requires ServiceT to be a base of T"); ... } }; 

Now, I would like to BOOST_CHECK it!

 class A {}; class B {}; BOOST_AUTO_TEST_CASE(registering_incompatible_types_should_raise_a_static_assert_failure) { BOOST_CHECK_STATIC_ASSERT_FAILURE(IFoo< A* >().as< B* >()); } 

I want this BOOST_CHECK to compile and pass as well. But, I want the user code to be compromised when he really does something like this:

 void myAwesomeMethod() { auto result = IFoo< A* >().as< B* >(); ... } 

Any idea?

+4
source share
1 answer

For your information, compilation failure usually prevents compilation ... that is why they are here in the end.

I can imagine two ways to do what you offer:

  • using SFINAE
  • using special compiler options

SFINAE

Literally, SFINAE means: Replacement error is not an error. It applies to the context of the template and allows functions that are inadequate to be discarded from the overload set. Using SFINAE gave rise to the idea of ​​conceptually validating and categorizing properties using features used to support these validations.

In your case, this means that if you can somehow put the expression that you want to test in the context in which SFINAE can be used, you can try and find that the particular function has been effectively dropped.

For instance:

 #include <iostream> #include <utility> struct Foo {}; struct Bar {}; template <typename T> auto foo(T t) -> decltype(std::declval<Foo>() + t) { std::cout << "T\n"; } void foo(...) { std::cout << "ellipsis\n"; } int main() { foo(Bar()); } 

gives:

 ellipsis 

(see ideone ), although there is no operator+(Foo, Bar) defined anywhere.

Unfortunately, this may not work in all cases (not sure yet), but it should be portable on all compatible compilers.

Specifier

Another possibility is to use special compiler functions. In compiler test suites, you need to make sure that these compilers correctly diagnose errors and in your case emit an error when the static_assert condition is static_assert . Therefore, compilers probably have hooks for this.

For example, in the Clang test suite, you can find the SemaCXX/static-assert.cpp :

 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x int f(); static_assert(f(), "f"); // expected-error {{static_assert expression is not an integral constant expression}} static_assert(true, "true is not false"); static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}} void g() { static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}} } class C { static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}} }; template<int N> struct T { static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed "N is not 2!"}} }; T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}} T<2> t2; template<typename T> struct S { static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static_assert failed "Type not big enough!"}} }; S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}} S<int> s2; 

-fsyntax-only avoid code generation and -verify means that the compiler checks that the specified expected-note , expected-warning and expected-error executed correctly.

If this is not the case, then the compiler will return with an error code. Of course, this will most likely be compiler specific.

+6
source

Source: https://habr.com/ru/post/1391106/


All Articles