2011-02-04 3 views
2

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

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

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

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

+2

Конечно, мы должны использовать только этот макрос на типы POD. (Хотя последний бросок должен быть 'ptrdiff_t', а не' unsigned long'. Не говоря уже о том, что 'offsetof' уже существует в' '.) – GManNickG

+1

@ Vlad .... brrrrrr .... и ... вы сказали «так же просто, как« .... urgh ... :-( –

+0

@GMan: Есть трюк, чтобы заставить его работать для не-POD-типов. Я просто хочу, чтобы это было просто. И 'offsetof' в стандартной библиотеке C не поддерживает это. –

ответ

3

Хотя я не могу получить то, что ваш компилятор, следующий код может быть составлен VC8, ideone (GCC-4.3.4), и Комео онлайн:

struct A { int i; }; 
template<size_t> struct S; 

int main() { 
    S< offsetof(A, i) > *p; 
} 

Gcc имеет __offsetof__ расширение , У VC, похоже, есть возможность принять константу не компиляции для шаблона аргументами странно. Что касается Comeau, я понятия не имею о внутреннем состоянии Comeau 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; 
} 

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

+0

Что вы подразумеваете под «принимать нестатические константы для аргумента шаблона»? – aschepler

+0

@aschepler: Извините за мою вводящую в заблуждение формулировку. Я имею в виду постоянную времени компиляции. VC8, кажется, расширяет 'offsetof (A, i)' в приведенном выше коде до '(size_t) & reinterpret_cast ((((* *) 0) -> i))'. Возможно, это невозможно использовать как константу времени компиляции (аргумент шаблона) . Я отредактировал ответ. –

+0

@Ise: Странно, Комо позволяет результат этого выражения быть аргументом шаблона. Это именно то, что мне нужно. Это '__builtin_offsetof' в gcc выражение времени компиляции? Я думал о преобразовании указателей в интегральные типы .. что-то в этом роде, но не могу точно подумать, как это сделать. –

1

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

+0

@Jerry: 'offsetof' из стандартной библиотеки C не поддерживает типы POD. В моем примере также нет моего простого макроса, но я обычно использую полнофункциональный код для своего кода. Именно по этой причине я придерживаюсь привычного. –

+0

@ Vlad Lazerenko: Почему вы думаете, что 'offsetof' не поддерживает типы POD? –

+0

@Jerry: http://stackoverflow.com/questions/1129894/why-cant-you-use-offsetof-on-non-pod-strucutures-in-c –

0

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

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

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

+0

g ++, вероятно, может вычислить, что во время компиляции, к сожалению, он, конечно же, не позволит вам использовать результат этого вычисления как константы времени компиляции. –

+0

Вы забыли ptrdiff_t ;-) Далее я думаю, что вы не отвечаете на вопрос OP. Интегральное константное выражение является четко определенным термином в стандарте C++, для которого запрашивает OP. Вопрос НЕ в том, оптимизирован ли какой-либо расчет смещения компилятором, но как получить константу, которая работает как аргумент неттипа шаблона (возможно, чтобы сделать это вручную внутри генератора кода, управляемого шаблоном). – Dude