views:

271

answers:

5

Is there a way to test compile-time errors, but without actually generating the error? For example, if I create a class which is non-copyable, I'd like to test the fact that trying to copy it will generate a compiler error, but I'd still like to execute the other runtime tests.

struct Foo {
    int value_;
    Foo(int value) : value_(value) {}
  private:
    Foo(const Foo&);
    const Foo& operator=(const Foo&);
};

int main()
{
    Foo f(12);
    assert(f.value_ == 12);
    assert(IS_COMPILER_ERROR(Foo copy(f);));
} // Would like this to compile and run fine.

I guess this can't be done as simply as that, but is there an idiomatic way to do this, or should I roll my own solution (maybe using scripts compiling separate tests files and testing the results?)?

N.B.: I took non-copyable only to illustrate my point, so I'm not interested in answers about using boost::noncopyable and such.

+1  A: 

Unfortunately there is no easy way to test a compile error in the way you want to, I've also wanted to do this before.

Anyways if your tests are small enough you can write short uncompilable code, like your sample, and verify with a script if the errors generated are correct or not (again you just said it).

An example of this sort of thing would be Unix's configure scripts, in more than a few scripts I've seen them try to compile little samples to verify the version/abilities of the compiler, to configure the makefile correctly.

So at least you can know you're not alone. Now if you wrote a successful test framework for this sort of thing you'd probably become famous :)

Edit: You could possibly also use a #define that either tries or not compile uncompilable code something like this:

#ifdef _COMPILETEST
#define TRY_COMPILE(...) (__VA_ARG__)
#else
#define TRY_COMPILE(...)
#end

Note that this is something I just though about and there are probably many problems with this pattern, but it might serve as a seed for some better ideas.

Robert Gould
Well, that's what I feared...at least I have a new project to work on in my (scarce) spare time :p!
Luc Touraille
Yeah its unfortunate. But remember you could become famous ;)
Robert Gould
For the moment, I use something a little similar to your edit: I have a cpp file that either includes test_compile.h or test_runtime.cpp, depending on a compiler constant.
Luc Touraille
A: 

Feel free to write a test framework that can do it. A lot of C++ programmers would appreciate it. :)

jalf
+7  A: 
Dushara
This editor is chopping half the Makefile and I don't know why. It should have 2 other lines:test2: must_pass_but_fails.cpp @$(PASSTEST) $
Dushara
A: 

boost.type_traits seems to have what you are looking for.

Luc Hermitte
Even though the Boost Type Traits library provides several very convenient features, it cannot really solve the problem exposed here (not to mention more complex cases).
Luc Touraille
For example, I would expect boost::is_convertible<Foo, Foo>::value to be false (since Foo is not copyable), but I get a compiler error, so the problem is still there.
Luc Touraille
I was thinking to has_nothrow_copy, however, it seems to work only with recent versions of VC++.
Luc Hermitte
Well, has_nothrow_copy<Foo> is indeed false, but only because Foo copy constructor doesn't have an empty exception specification, not because it is private. So I agree boost::type_traits can be useful, but not to adress the kind of issues evoked in the question.
Luc Touraille
+2  A: 

BTW the only build system I know that allows such test out-of-the-box is Boost.Build:

Check here" http://beta.boost.org/boost-build2/doc/html/bbv2/builtins/testing.html

For example,

# in your Jamfile
compile-fail crappy.cpp ;

.

int main()
{
  my crappy cpp file
}

For more examples just grep -R compile-fail in your BOOST_TOP_DIR\libs directory.

Alexander Poluektov