Смещение члена класса / структуры данных C ++ в виде константного выражения - PullRequest
2 голосов
/ 04 февраля 2011

Сдвиг элемента данных так же прост:

#define MEMBER_OFFSET(Type, Member) \
    ((unsigned long)(((char *)&((Type *)0)->Member) - (char *)0));

Я хочу сделать это постоянным выражением времени компиляции (или использовать черты типа).Например, чтобы использовать его для реализации решений на основе SFINAE, используя смещения элементов, статические утверждения и т. Д.

ОБНОВЛЕНИЕ: Вопрос в том, как сделать это выражение времени компиляции.Не работает ли он с типами POD, или есть стандартный макрос в библиотеке C и т. Д.

Ответы [ 3 ]

3 голосов
/ 04 февраля 2011

Хотя я не могу понять, каков ваш компилятор, следующий код может быть скомпилирован 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, похоже, обладает способностью принимать константу времени некомпиляции для аргумента шаблона странным образом.Что касается Comeau, я, к сожалению, понятия не имею о внутреннем из offsetof Comeau.

Между прочим, хотя это не ответит на ваш вопрос напрямую, как для цели 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;
}

Надеюсь, это поможет.

1 голос
/ 04 февраля 2011

В стандартной библиотеке C уже есть offsetof, которая делает то, что пытается (но вы можете использовать ее без UB). К сожалению, применение его к типу, отличному от POD, по-прежнему дает неопределенное поведение, поэтому для многих C ++ оно все еще бесполезно.

0 голосов
/ 04 февраля 2011

Во-первых, ставить точку с запятой в макросе - плохая идея - ее нельзя использовать в большом выражении.

Во-вторых, не рекомендуется использовать unsigned long, когда есть совершенно хорошие типы, специально разработанные для указателей (а именно size_t и ssize_t, представленные в stdint.h). Эти типы особенно полезны при использовании 32- и 64-битных архитектур - и GCC имеет расширение для printf "% zu", чтобы использовать правильный размер слова.

G ++ вычисляет это во время компиляции, по крайней мере с -O2 и -O3 с типами POD

...