получить смещение элемента кортежа - PullRequest
7 голосов
/ 19 марта 2011

Я написал следующий код, чтобы получить смещение элемента кортежа

template<size_t Idx,class T>
 constexpr size_t tuple_element_offset() {
        return static_cast<size_t>(
                    reinterpret_cast<char*>(&std::get<Idx>(*reinterpret_cast<T*>(0))) - reinterpret_cast<char*>(0));
    }

На самом деле это похоже на реализацию макроса offsetof . Это выглядит некрасиво, но компилируется и отлично работает на gcc-4.6

typedef std::tuple<int,char,long> mytuple;

mytuple var = std::make_tuple(4,'c',1000);
char * ptr = reinterpret_cast<char*>(&var);
long * pt = reinterpret_cast<long*>(ptr+tuple_element_offset<2,mytuple>());

std::cout << *pt << std::endl;

печатает "1000".

Я не слишком много знаю о constexpr, поэтому мои вопросы:

  1. Законно ли это с ++?
  2. Более важно, почему мне разрешено звонить std :: get (который не является constexpr) внутри функции constexpr?

Насколько я понимаю constexpr, компилятор вынужден оценивать результат выражения во время компиляции, поэтому на практике не может произойти разыменование нуля.

1 Ответ

5 голосов
/ 19 марта 2011

Законно ли C ++?

Если под «легальным» вы подразумеваете «правильно сформированный», то да.

Если под «легальным» вы подразумеваете «допустимый» и будет работать на любом компиляторе и стандартной библиотекереализации, то нет, потому что std::tuple не является POD.

Почему мне разрешено вызывать std::get (что не constexpr) внутри constexpr функции?

По сути, функция constexpr не обязательно должна состоять только из константного выражения. Если вы попытаетесь использовать функцию tuple_element_offset() в константном выражении, вы получите ошибку компиляции.

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

Черновик C ++ 0x имеет хорошийпример (из 5.19 / 2):

constexpr const int* addr(const int& ir) { return &ir; } // OK

// OK: (const int*)&(const int&)x is an address contant expression
static const int x = 5;
constexpr const int* xp = addr(x); 

// Error, initializer for constexpr variable not a constant expression; 
// (const int*)&(const int&)5 is not a constant expression because it takes
// the address of a temporary
constexpr const int* tp = addr(5);
...