blob: a41ebb57c47d3ca2af3dacbbbaa8f60ac1e9aef3 [file] [log] [blame]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CRUBIT_SUPPORT_OFFSETOF_H_
#define CRUBIT_SUPPORT_OFFSETOF_H_
#include <cstddef>
namespace crubit::details {
// OffsetOfHelper is very similar to `std::type_identity_t`, except that it
// provides a way to wrap `T` in parens without running into an error message
// like:
// error: expected a type
// static_assert(CRUBIT_OFFSET_OF(field, TestStruct) == 0, "");
// ^
// note: expanded from macro 'CRUBIT_OFFSET_OF'
// offsetof((T), member)
// ^
// or (when using `std::type_identity_t` with parens around T):
// error: expected expression
// static_assert(CRUBIT_OFFSET_OF(offset0, BasicStruct) == 0, "");
// ^
// note: expanded from macro 'CRUBIT_OFFSET_OF'
// offsetof(std::type_identity_t<(T)>::type, member)
// ^
// or (when using `std::type_identity_t` with different parens placement):
// error: expected a type
// static_assert(CRUBIT_OFFSET_OF(field, TestStruct) == 0, "");
// ^
// note: expanded from macro 'CRUBIT_OFFSET_OF'
// offsetof((crubit::type_identity_t<T>::type), member)
// ^
//
// The errors are avoided by allowing passing `T` via `void(T)` syntax through
// the single specialization below.
template <typename T>
struct OffsetOfHelper;
template <typename T>
struct OffsetOfHelper<void(T)> {
using Type = T;
};
} // namespace crubit::details
// CRUBIT_OFFSET_OF is a wrapper around the standard `offsetof` macro [1] that
// adds support for using a type name (i.e. `...`) that contains commas (e.g.
// `ClassTemplateWithTwoTemplateParameters<int, int>`).
//
// CRUBIT_OFFSET_OF doesn't require wrapping the type name in an extra set of
// parens. This aspect is achieved by making CRUBIT_OFFSET_OF a variadic macro
// (i.e. accepting 2 *or more* arguments) and by making `...` the last
// parameter (i.e. using a different order of macro parameters than the standard
// `offsetof`).
//
// See the doc comments of OffsetOfHelper above for an explanation why wrapping
// the type name in an extra parens is not sufficient for the standard
// `offsetof` macro.
//
// [1] https://en.cppreference.com/w/cpp/types/offsetof
#define CRUBIT_OFFSET_OF(member, ...) \
offsetof(::crubit::details::OffsetOfHelper<void(__VA_ARGS__)>::Type, member)
#endif // CRUBIT_RS_BINDINGS_FROM_CC_SUPPORT_OFFSETOF_H_