Смещение элемента данных класса/структуры C++ как постоянное выражение

StackOverflow https://stackoverflow.com/questions/4899476

Вопрос

Взять смещение элемента данных так же просто:

#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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top