2014-12-25 18 views
7

Sto provando a scrivere una struttura per calcolare l'offset del puntatore tra una base e una classe derivata come espressione costante in C++ 03. Il codice è il seguente:Perché il typecasting di un intero letterale a un valore del puntatore produce un'espressione non const?

template <typename Base, typename Derived, typename Via = Derived> 
struct OffsetToBase 
{ 
    static const std::ptrdiff_t val = 
     (const char*const)static_cast<Base*const>(static_cast<Via*const>((Derived*const)(1u << 7))) - 
     (const char*const)(1u << 7); 
}; 

Il codice viene compilato in GCC, ma non in clang e VC. L'errore prodotto da clang e VC in sostanza dice che l'inizializzatore non è un'espressione costante con clang che sottolinea ulteriormente la sottoespressione (Derived*const)(1u << 7).

Quindi, la mia domanda è che cosa dicono gli standard di questo? E se l'inizializzatore non si qualifica come un'espressione costante secondo gli standard, allora qual è il ragionamento alla base di questo?

UPDATE: per il vostro interesse, ho trovato questi due dibattiti:

"Initializer element is not constant" error for no reason in Linux GCC, compiling C

About cast in integer constant expression (in standard C)

Ma non credo che le stesse regole si applicano a C++.

risposta

1

Questo non è un'espressione costante, secondo la mia lettura della norma:

5.19 Le espressioni costanti

...

Un condizionale espressione è una costante di base espressione a meno che non coinvolga uno dei seguenti

...

- una sottrazione (5.7) in cui entrambi gli operandi sono puntatori;

L'espressione sottrae un puntatore di carattere const da un altro. Ciò sembra squalificare l'intera cosa dall'essere considerata un'espressione costante.

Nel tuo caso, entrambi i puntatori nelle domande stesse sono valori costanti, valori fittizi. Se è così, allora è teoricamente possibile capire il risultato della loro sottrazione, come espressione costante, ma non lo è. Qualunque cosa.

Non penso che sia nemmeno necessario utilizzare la sottrazione del puntatore o che un cast statico di un puntatore funzioni qui, è necessario eseguire un cast statico su un riferimento. Le seguenti opere per me, almeno con GCC:

class B { int a; }; 
class C { int b; }; 

class A : public B, public C {}; 

int main() 
{ 
    static const long n=(long)&static_cast<C &>(*(A *)0); 
    return 0; 
} 
+3

Ho paura che questo è UB: stai dereferenziazione un puntatore nullo –

+0

Naturalmente 'static_cast' lavora su puntatori. Esegui la sottrazione _after_ la conversione in numero intero. – Oktalist

+0

Grazie per la citazione dallo standard.Tuttavia, non sembra che risolva il vero problema, dato che il seguente codice (che gira in 'const std :: ptrdiff_t' invece di' const char * const') non esegue il compilatore su clang e VC: 'template struct OffsetToBase { static const std :: ptrdiff_t val = (const std :: ptrdiff_t) static_cast (static_cast ((Derived * const) (1U << 7))) - (const std :: ptrdiff_t) (1u << 7); }; ' – Lingxi

Problemi correlati