Смещение элемента данных класса/структуры C++ как постоянное выражение
-
28-10-2019 - |
Вопрос
Взять смещение элемента данных так же просто:
#define MEMBER_OFFSET(Type, Member) \
((unsigned long)(((char *)&((Type *)0)->Member) - (char *)0));
Я хочу сделать это постоянным выражением времени компиляции (или использовать признаки типа).Например, чтобы использовать его для реализации решений на основе SFINAE с использованием смещений членов, используйте статические утверждения и т. д.
ОБНОВЛЯТЬ: Вопрос в том, как сделать это выражением времени компиляции.Неважно, работает ли он с типами POD или есть ли стандартный макрос в библиотеке C и т. д.
Решение
Хотя я не могу получить то, что такое ваш компилятор, следующий код может быть составлен с помощью VC8, IDEONE (GCC-4.3.4) и Comeau Online:
struct A { int i; };
template< size_t > struct S;
int main() {
S< offsetof( A, i ) > *p;
}
Gcc имеет __offsetof__
расширение.Кажется, что VC может странно принять постоянную некомпиляцию для аргумента шаблона.Что касается Комо, то я понятия не имею о внутренней стороне Комо. offsetof
к сожалению.
Между прочим, хотя это не ответит на ваш вопрос напрямую, как и для цели Sfinae, поскольку постоянная указателя участника может использоваться в качестве аргумента шаблона, и вы можете специализироваться на нем, вы можете написать в качестве следующего:
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;
}
Надеюсь это поможет.
Другие советы
В стандартной библиотеке C уже есть код offsetof
, который выполняет то, что пытается сделать (но вы можете использовать его без UB).К сожалению, его применение к типу, отличному от POD, по-прежнему приводит к неопределенному поведению, поэтому для большинства C ++ он по-прежнему бесполезен.
Во-первых, ставить точку с запятой в макросе - плохая идея - ее нельзя использовать в больших выражениях.
Во-вторых, плохая идея использовать unsigned long
, когда есть совершенно хорошие типы, специально разработанные для указателей (а именно size_t и ssize_t, представленные в stdint.h).Эти типы особенно полезны при использовании 32- и 64-разрядных архитектур, а GCC имеет расширение printf, "% zu", для использования правильного размера слова.
G ++ вычисляет это во время компиляции, по крайней мере, с -O2 и -O3 с типами POD