obtenir le décalage d'un élément de tuple
Question
J'ai écrit le code suivant pour obtenir le décalage d'un élément de tuple
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));
}
Ceci est en fait similaire à la mise en œuvre du offsetof macro. Il semble laid, mais compilera et fonctionne très bien sur 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;
affiche "1000".
Je ne sais pas trop constexpr, donc mes questions sont:
- Est-il légal c ++?
- Plus important encore, pourquoi je suis autorisé à appeler std :: get (qui est non constexpr) l'intérieur d'une fonction constexpr?
Pour autant que je comprends constexpr, le compilateur est obligé d'évaluer le résultat de l'expression au moment de la compilation, donc pas de boîte zéro dereferentiation se produit dans la pratique.
La solution
Est-ce C ++ juridique?
Si vous voulez dire « bien formé » par « juridique » alors, oui.
Si par « légal » vous voulez dire « valide et fonctionne sur tous les compilateur et la mise en œuvre bibliothèque standard, puis, non, parce que std::tuple
n'est pas POD.
Pourquoi je suis autorisé à appeler
std::get
(ce qui estconstexpr
) dans une fonction deconstexpr
?
En fait, une fonction constexpr
ne doit pas nécessairement consister en juste une expression constante. Si vous avez essayé d'utiliser votre fonction tuple_element_offset()
dans une expression constante, vous obtiendrez une erreur de compilation.
L'idée est qu'une fonction pourrait être utilisable dans une expression constante dans certaines circonstances, mais pas dans d'autres, donc il n'y a pas une restriction qu'une fonction constexpr
doit toujours être utilisable dans une expression constante (car il n'y a pas une telle une restriction, il est également possible qu'une fonction constexpr
particulière pourrait ne jamais être utilisable dans une expression constante, comme cela est le cas avec votre fonction).
Le projet de C ++ 0x a un bon exemple (de 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);