4

In our unit tests we have a few lines like:

// Should not compile - manually checked
// auto val = ::Utils::LexicalCast<const char*>(5);

And indeed if I uncomment this code it fails within LexicalCast at a static_assert:

static_assert(!std::is_pointer<ToType>::value, "Cannot return pointers from a LexicalCast");

As, in this case it would be unclear who owns the memory.

So my question is, using any advanced C++ features (I was thinking of SFINAE mainly but am not well versed in it) is it possible to check if something wouldn't compile due to a static_assert in the function called? I don't mind detection at runtime or compile time, and dont mind macros, etc, as these are tests.

EDIT: e.g. I want something like

ASSERT_DOESNT_COMPILE(::Utils::LexicalCast<const char*>(5));
Mike Vine
  • 9,468
  • 25
  • 44
  • 3
    Simple case: provide defines that conditionally enable different parts of the code. Then have a 'test driver' that runs the compiler with the different defines and checks that the compiler fails when it should. You might also want to look into boost, I think they have similar tests (compile/does not compile) in the libraries – David Rodríguez - dribeas Feb 06 '14 at 15:25
  • Run the compiler (exe or lib) from you unit tests, and check result ? – Jarod42 Feb 06 '14 at 15:26
  • 1
    Can you detect uncompilable code? Yes> Try to compile it, if it fails, it is uncompilable. – Davidbrcz Feb 06 '14 at 15:26
  • I appreciate all these answers of actually compiling and checking that, but that would involve a fair bit of rejigging the unit test framework so I'd really prefer to have something like this happen within normal successful build and run flow. Appreicate this may not be possible though. – Mike Vine Feb 06 '14 at 15:29
  • Perhaps I'm missing something, but if a `static_assert` fails, your code does not compile. If your code does not compile, how are you running a unit test on it? – Zac Howland Feb 06 '14 at 15:40
  • @Zac Howland I'm not - like I said its commented out code with a comment that says 'this SHOULDN'T compile'. I want to unit test the fact that it shouldn't compile by having it fail to compile in a detectable but not fatal way. – Mike Vine Feb 06 '14 at 15:51
  • Possible duplicate: http://stackoverflow.com/questions/17408824/how-to-write-runnable-tests-of-static-assert – proxi Feb 06 '14 at 16:23
  • @MikeVine But in order to unit test something, it must compile. You cannot unit test code that does not compile ... – Zac Howland Feb 06 '14 at 16:42
  • @Zac Howland: Which is why I mentioned SFINAE which rejects ill formed choices in a non fatal kind of way. I've tried to use SFINAE to do something like this but I came to the conclusion you can't. But maybe someone whos a better SFINAE ninja than me can think of a cunning way... – Mike Vine Feb 06 '14 at 17:01
  • @MikeVine I think you are missing my point. Unit tests are supposed to test the logic for your use case to make sure it does the correct action. For example, `int Multiply(int a, int b)` should return the result of `a * b`. `static_assert` is used to make sure you do not try to write invalid code. You are attempting to use unit tests to make sure you do not write invalid code ... that is not their purpose. – Zac Howland Feb 06 '14 at 17:09
  • OK I'm saying unit test when I just mean our generic testing framework which can test a lot of things. My bad. But it can't currently do differential compilation so I'd like to 'test' that a templated function can't compile in specific circumstances. – Mike Vine Feb 06 '14 at 17:24
  • If you want to test that you've written your static asserts properly using your test suite, then define your own `my_static_assert` function that calls `static_assert` under normal circumstances, and throws a logic error if you compile with a specified flag. The only time I could see this being useful is if you are developing a library that someone outside your team is expecting to use - and even then its use would be questionable. – Zac Howland Feb 06 '14 at 17:35
  • Not an exact duplicate, but there's another question along these same lines here: http://stackoverflow.com/questions/17408824/how-to-write-runnable-tests-of-static-assert?lq=1 – Adrian McCarthy Feb 06 '14 at 18:25

2 Answers2

1

The following example shows that SFINAE cannot help with static_assert:

#include <type_traits>

// Fall back version that will always compile
template<class T>
void foo(T) {}

// Specific version using a static_assert that may or may not fire
template<class T>
void foo(T*) {
    static_assert(std::is_same<T, char>::value, "Boo");
}

int main(int argc, char** argv) {
    // This could call the fall back version, but the static_assert fires anyway
    foo((int*)0);
    return 0;
}

When compiled with clang++ (3.4) and g++ (4.8.1), the static_assert fires although according to SFINAE it shouldn't. My conclusion is SAFIAE, i.e. Static_Assert Failure Is An Error.

gTcV
  • 2,446
  • 1
  • 15
  • 32
  • You could of course replace all `static_assert`s with `std::enable_if` and try to build some SFINAE construct for that, but that would mean you forbid using a language feature and is therefore hardly desirable. I think your only option is to write a script which tries to compile all expressions that should not compile, and asserts that the compiler returns with an error for each of them. I don't think it's worth the effort, but you can judge that better than I can. – gTcV Feb 06 '14 at 19:07
-2

Perhaps too obvious, but ff you're only interested in this particular (static_assert) case, you can simply re#define it to something else:

#include <cassert>
#include <cstdio>
using namespace std;

#define static_assert(flag, msg) { assert(flag); }

int main()
{
    static_assert(false, "static_assert compile time");

    return 0;
}
proxi
  • 1,243
  • 10
  • 18
  • 2
    Sorry, -1. This is illegal from the language point of view, and wouldn't work at all if the static assert is used outside of a function body (which is possible, since it's a type of declaration). – Angew is no longer proud of SO Feb 06 '14 at 15:48
  • This was actually an interesting option so I gave this a go - unfortunately the code didn't compile later on after the static_assert, so even making this a runtime failure (by throwing an exception for instance in the #define) still failed to compile – Mike Vine Feb 06 '14 at 15:49
  • I do realize it is incorrect (redefining a keyword), but e.g. GCC has no problems with it. Why "wouldn't work at all if the static assert is used outside of a function body"? Obviously you have to redefine it early enough, but in unit test where you have full control over environment that should be possible. – proxi Feb 06 '14 at 15:54
  • Mike, can you give example? – proxi Feb 06 '14 at 15:55
  • And: it has been done before. See e.g.: https://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/config.h?view=markup&pathrev=192136 – proxi Feb 06 '14 at 15:56
  • @proxi that code only defined a C++11 keyword pre-C++11. As far as C++03 goes, `static_assert` is not a keyword. – rubenvb Feb 06 '14 at 16:12
  • 2
    @proxi `static_assert` can also be used for example in the body of a `class` or `struct`, whereas the old C `assert` can only be used in a function, as it is a runtime thing. – JorenHeit Feb 06 '14 at 16:16
  • @JorenHeit Or even at namespace scope. It's just a declaration. – Angew is no longer proud of SO Feb 06 '14 at 18:15