Search code examples
c++capnproto

Cap'n proto generated c++ source doesn't compile


I'm having trouble with this piece of capnp code:

struct Result(Success, Error) {
    union {
        success @0 :Success;
        error   @1 :Error;
    }
}

I created and compiled the c++ source like this:

capnp compile -oc++ test.capnp
g++ -o test.capnp.o test.capnp.c++ `pkg-config --cflags capnp` -std=c++11

And I'm getting this same error (and the same with ERROR instead of SUCCESS) at multiple locations in the generated header file:

error: type/value mismatch at argument 2 in template parameter list for ‘template<class Success, class Error> struct Result’
   KJ_IREQUIRE(which() == Result<Success, Error>::SUCCESS,
   ^
error:   expected a type, got ‘true’
error: expected primary-expression before ‘>’ token
   KJ_IREQUIRE(which() == Result<Success, Error>::SUCCESS,
                                               ^
error: ‘::SUCCESS’ has not been declared
   KJ_IREQUIRE(which() == Result<Success, Error>::SUCCESS,
                                                ^

Here is one of the definitions that g++ complains about:

template <typename Success, typename Error>
inline  ::capnp::ReaderFor<Success> Result<Success, Error>::Reader::getSuccess() const {
  KJ_IREQUIRE(which() == Result<Success, Error>::SUCCESS,
              "Must check which() before get()ing a union member.");
  return ::capnp::_::PointerHelpers<Success>::get(
      _reader.getPointerField(0 * ::capnp::POINTERS));
}

I really don't understand why g++ doesn't accept this...

I use capnproto 0.5.3 (first encountered this issue in 0.5.2 and then updated to see if that would help) and g++ 4.9.2.


Solution

  • The rest of this answer is outdated. This issue should not appear anymore since capnp version 0.6.0.


    Just when I was done writing my question, I wanted to test this with clang as well, and it actually made me find the error. I still chose to post the question as I was already done writing. The problem is that KJ_IREQUIRE is a macro, and as macros are a thing the preprocessor handles, their semantics are very ugly. The comma in the template arguments for Result gets interpreted as an argument delimiter for the macro, leading to this really unhelpful error message in g++, but a much nicer one in clang.

    To work around this, you can add another set of brackets around the arguments of KJ_IREQUIRE. I hope this bit of documentation can help someone!