get the offset of a tuple element
I have wrote the following code to get the offset of a tuple element
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));
}
This is actually similar to the implementation of the offsetof macro. It looks ugly, but compiles and works fine on 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;
prints "1000".
I don't know too much about constexpr, so my questions are:
- Is it legal c++?
- More important, why I am allowed to call std::get (which is non constexpr) inside a constexpr function?
As far as I understand constexpr, the compiler is forced to evaluate the result of the expression at compile time, so no zero-dereferentiation can occurs in pract开发者_运维问答ice.
Is it legal C++?
If by "legal" you mean "well-formed," then, yes.
If by "legal" you mean "valid and will work on any compiler and Standard Library implementation, then, no, because std::tuple
is not POD.
Why I am allowed to call
std::get
(which is notconstexpr
) inside aconstexpr
function?
Basically, a constexpr
function doesn't necessarily have to consist of just a constant expression. If you tried to use your tuple_element_offset()
function in a constant expression, you'd get a compilation error.
The idea is that a function might be usable in a constant expression in some circumstances but not in others, so there isn't a restriction that a constexpr
function must always be usable in a constant expression (since there isn't such a restriction, it's also possible that a particular constexpr
function might never be usable in a constant expression, as is the case with your function).
The C++0x draft has a good example (from 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);
精彩评论