Ottieni l'offset di un elemento tupla
Domanda
Ho scritto il seguente codice per ottenere l'offset di un elemento tupla
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));
}
Questo è in realtà simile all'implementazione del offsetf macro. Sembra brutto, ma compila e funziona bene su 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;
stampe "1000".
Non so molto su Conmexpr, quindi le mie domande sono:
- È legale C ++?
- Ancora più importante, perché mi è permesso chiamare std :: get (che non è costexpr) all'interno di una funzione costexpr?
Per quanto ho compreso Contexpr, il compilatore è costretto a valutare il risultato dell'espressione al momento della compilazione, quindi non è possibile verificarsi alcuna dereferenziazione zero.
Soluzione
È legale C ++?
Se per "legale" intendi "ben formato", allora sì.
Se per "legale" intendi "valido e lavorerà su qualsiasi compilatore e implementazione della libreria standard, allora no, perché std::tuple
non è pod.
Perché mi è permesso chiamare
std::get
(che non èconstexpr
) all'interno di A.constexpr
funzione?
Fondamentalmente, a constexpr
La funzione non deve necessariamente consistere solo in un'espressione costante. Se hai provato a usare il tuo tuple_element_offset()
Funzionare in un'espressione costante, otterresti un errore di compilazione.
L'idea è che una funzione potrebbe essere utilizzabile in un'espressione costante in alcune circostanze ma non in altre, quindi non c'è una restrizione che a constexpr
La funzione deve essere sempre utilizzabile in un'espressione costante (poiché non esiste una tale restrizione, è anche possibile che un particolare constexpr
La funzione potrebbe non essere mai utilizzabile in un'espressione costante, come nel caso della funzione).
La bozza C ++ 0x ha un buon esempio (da 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);