Statically get offset of member variable
First of, as requested, you're goal is not achievable as the type of a
impacts the offst of a
inside B
:
struct B
{
int some_variables[256];
A</* offset of a inside B */> a;
};
This is alignment.
You could use the standard macro offsetof
. This implies two things:
- Since
offsetof(type, member)
is well-defined only for standard-layouttype
s, the enclosing type must be standard-layout, - and since
offsetof
can only be "called" on complete types, its statically-computed result can only be set to the subobject dynamically; it canoot be a template non-type parameter, but can be a constructor argument.
Full program
#include <cassert>
#include <cstdint>
#include <cstddef>
struct Location
{
Location(std::size_t offset) : offset_(offset) {}
std::size_t offset_;
operator std::intptr_t () const { return reinterpret_cast<std::intptr_t>(this) - offset_; }
};
struct SomeType
{
int some_variables[256];
Location location = offsetof(SomeType, location);
};
int main()
{
SomeType obj;
assert(reinterpret_cast<std::intptr_t>(&obj) == obj.location); // does pass
}
live demo
But as you commented, this is quite useless as Location
could be simply defined as
template<class T>
struct Location
{
Location(T* location) : location_(location) {}
T* location_;
operator T* () const { return location; }
};
and initialized with Location location = this;
.
Determining struct member byte-offsets at compile-time?
offsetof
is a compile time constant, if we look at the draft C++ standard section C.3
C standard library paragraph 2 says:
The C++ standard library provides 57 standard macros from the C library, as shown in Table 149.
and the table includes offsetof
. If we go to the C99 draft standard section 7.17
Common definitions paragraph 3 includes:
offsetof(type, member-designator)
which expands to an integer constant expression that has type size_t, the value of
which is the offset in bytes [...]
C++ class/structure data member offset as constant expression
Though I can't get what your compiler is,
the following code can be compiled by VC8, ideone(gcc-4.3.4), and Comeau
online:
struct A { int i; };
template< size_t > struct S;
int main() {
S< offsetof( A, i ) > *p;
}
Gcc has __offsetof__
extension.
VC seems to have a capability to take a non-compile-time constant for a template
argument strangely.
As for Comeau, I have no idea about the internal of Comeau's offsetof
unfortunately.
Incidentally, though this won't answer your question directly, as for SFINAE
purpose, since a member pointer constant can be used as a template argument
and you can specialize on it, you can write as the following:
struct A {
int i, j;
};
template< int A::* > struct S;
template<> struct S< &A::i > { static char const value = 'i'; };
template<> struct S< &A::j > { static char const value = 'j'; };
int main() {
cout<< S< &A::i >::value <<endl;
cout<< S< &A::j >::value <<endl;
}
Hope this helps.
How to output the offset of a member in a struct at compile time (C/C++)
You can use the offsetof
macro, along with the C++11 static_assert
feature, such as follows:
struct A {
int i;
double db;
...
unsigned test;
};
void TestOffset() {
static_assert( offsetof( A, test ) == KNOWN_VALUE, "The offset of the \"test\" variable must be KNOWN_VALUE" );
}
Any way to do compile-time check if a member is the last class data member?
You can't really assert that a member is the last of its class today. The proposals in response to N3814 might make this possible, once accepted and implemented, but they're not available today. With what is currently available, you're still sunk because of padding issues (see Csq's example in the comments).
If you ignore that the limitations of padding, and limit yourself to "plain old data" cases without virtual inheritance, you can probably use the offsetof
macro, or suggestions from How to calculate offset of a class member at compile time? to perform the check you desire.
But in practice, per your comment about all your classes being protocol classes, can you not just do an assert against the known class size? It wouldn't catch cases when members were reordered, or when an addition fit within padding. But static asserts are really only there to prevent accidental incorrect changes, and you claim not to use padding. So go simple:
static_assert(sizeof(Foo) == 12, "Size of Foo has changed");
Compile time subclass byte-offset with virtual inheritance
Is it possible to compute, at compile time, the byte offset of a virtual base in an inheritance hierarchy?
No, because it's different for different object instances. It is not a property of the class.
Let's look at your example. B
has a virtual base class A
. So B
has to have some byte offset to an A
. The same is true for C
.
However, D
inherits a virtual A
through both B
and C
. The whole point of virtual
inheritance is that, if you inherit the same base class, then all of the paths to reach that base class will refer to the same subobject of the dynamic type. So D
only has a single instance of A
.
But where is it? The offsets that B
and C
use cannot both be correct. Unless... the offset itself is stored in the vtable.
Which is (basically) how virtual inheritance works. When you create a D
, it is the D
which is responsible for assigning where all of the virtual
ly inherited objects go. Those offsets will be different from when you create an object whose dynamic type is B
or C
.
There's no way to do what you're trying to do. Not without actually creating instances of objects. While C++20 does allow you to create instances of virtual types at compile time (so long as they have viable constexpr
constructors, so you can't do it with everything), you still can't do what you need. If you have pointers to two different types, to compute a byte offset between them, you have to reinterpret_cast
those pointers into integers or unsigned char*
s. And reinterpret_cast
is forbidden at compile-time (and bit_cast
isn't constexpr
when given a pointer type or a type that contains a pointer).
Related Topics
Gcc 7, -Wimplicit-Fallthrough Warnings, and Portable Way to Clear Them
Conversion from 'Myitem*' to Non-Scalar Type 'Myitem' Requested
Segmentation Fault Before Main() When Using Glut, and Std::String
How to Perform Rgb->Yuv Conversion in C/C++
Can a Lambda Capturing Nothing Access Global Variables
How to Know When a New Usb Storage Device Is Connected in Qt
Why Default Return Value of Main Is 0 and Not Exit_Success
For-Loop in C++ Using Double Breaking Out One Step Early, Boundary Value Not Reached
Modifying Reference Member from Const Member Function in C++
What Is Double Evaluation and Why Should It Be Avoided
Using Std::Variant with Recursion, Without Using Boost::Recursive_Wrapper
Should Function Declarations Include Parameter Names
A Better Way to Split a String into an Array of Strings in C/C++ Using Whitespace as a Delimiter
Absence of Typeof Operator in C++03
Why Can't Operator () of Stateless Functor Be Static
Has a Std::Byte Pointer the Same Aliasing Implications as Char*