4

Can offsetof be used with a type obtained through decltype? Is either of those cases valid C++11?

struct S {
  int i;
  int j { offsetof(decltype(*this), i) };  // case 1
  S() : i(offsetof(decltype(*this), j)) {}; // case 2
} inst1;

int main() {
  struct {
    int i;
    int j { offsetof(decltype(*this), i) }; // case 3
  } inst2;
  return 0;
}

None of it compiles under Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn), with the error

error: offsetof requires struct, union, or class type, 
'decltype(*this)' (aka '<anonymous struct at ../qxjs3uu/main.cpp:4:4> &') invalid

It also seems to crash MSVC 19.00.23106.0(x86) with an internal error:

Compiled with  /EHsc /nologo /W4 /c
main.cpp
main.cpp(3): error C2062: type 'S &' unexpected
[...]
main.cpp(4): fatal error C1903: unable to recover from previous error(s); stopping compilation
Internal Compiler Error in c:\tools_root\cl\bin\i386\cl.exe.  You will be prompted to send an error report to Microsoft later.

Did I think of something that no test case writers thought of?

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313

2 Answers2

6

The result of dereferencing a pointer is an lvalue (and itself is an expression), thus decltype(*this) gives you type S&:

§ 7.1.6.2 [dcl.type.simple]/p4:

The type denoted by decltype(e) is defined as follows:

— [...]

— otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;

To use it as an argument to offsetof, you'd need to remove a reference from a type obtained from the decltype() specifier:

offsetof(std::remove_reference<decltype(*this)>::type, i)

DEMO

Community
  • 1
  • 1
Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
  • Wonderful, that's exactly what I needed. I didn't realize that `offsetof` was such a type connoisseur that a mere reference threw it off :) – Kuba hasn't forgotten Monica Aug 27 '15 at 12:30
  • @KubaOber it's not `offsetof`'s fault; it's much more that references are weird. – The Paramagnetic Croissant Aug 27 '15 at 18:25
  • 2
    Careful reading of those error messages does reveal the `&` hidden in both of them. But one has to read `error: offsetof requires struct, union, or class type, 'decltype(*this)' (aka ' &') invalid` quite carefully to see it! – Toby Speight Aug 27 '15 at 20:19
  • 1
    @TobySpeight It also requires understanding that a *struct [...] type* literally means a struct and not reference-to-struct. That was precisely what I didn't know. I've put this to some (not necessarily good) use [in this answer](http://stackoverflow.com/a/32237219/1329652). – Kuba hasn't forgotten Monica Aug 27 '15 at 20:22
2

They can be used together. Take the example:

#include <iostream>
#include <string>
#include <stddef.h>

int main()
{
  struct S {
   int a;
   int b;
  };
  S instance;
  std::cout << "offset: " << offsetof(decltype(instance), b) << "\n";
  return 0;
}

Which prints offset: 4

I think your problem stems from using decltype(*this), which I'm not sure will do what you're expecting according to 5.1.1 of the C++11 standard.

patros
  • 7,719
  • 3
  • 28
  • 37