Ci sono casi in cui è disponibile un'origine della libreria e deve supportare in generale i parametri variabili, ma in pratica questi parametri sono comunemente costanti.Rilevamento costante in fase di compilazione C++
Quindi può essere possibile ottimizzare le cose mediante la gestione speciale di parametri costanti (ad esempio utilizzare array statici anziché allocazione heap), ma per questo è necessario determinare se qualcosa è una costante prima (o forse definire alcune macro, ma è meno conveniente).
Quindi ecco un'implementazione funzionante.
Aggiornamento: anche qui: http://codepad.org/ngP7Kt1V
- E 'davvero una valida C++?
- C'è un modo per sbarazzarsi di queste macro? (Is_const() non può essere una funzione perché la dipendenza funzione non funzionerà nell'espressione dimensione dell'array;. Inoltre non può essere un modello perché non accetterà un parametro variabile o)
Aggiornamento: Ecco un aggiornamento con qualcosa di più simile all'utilizzo previsto. Il compilatore non genererà alcun codice per il ramo if(N==0)
se N
non è 0. Lo stesso modo in cui possiamo passare a strutture di dati completamente diverse se vogliamo. Certo, non è perfetto, ma è per questo che ho postato questa domanda.
#include <stdio.h>
struct chkconst {
struct Temp { Temp(int x) {} };
static char chk2(void*) { return 0; }
static int chk2(Temp ) { return 0; }
};
#define is_const_0(X) (sizeof(chkconst::chk2(X))<sizeof(int))
#define is_const_0i(X) (sizeof(chkconst::chk2(X))>sizeof(char))
#define is_const(X) is_const_0((X)^((X)&0x7FFFFFFF))
#define const_bit(X1,bit) (is_const_0i((X1)&(1<<bit))<<bit)
#define const_nibl(X1,bit) const_bit(X1,bit) | const_bit(X1,(bit+1)) | const_bit(X1,(bit+2)) | const_bit(X1,(bit+3))
#define const_byte(X1,bit) const_nibl(X1,bit) | const_nibl(X1,(bit+4))
#define const_word(X1,bit) const_byte(X1,bit) | const_byte(X1,(bit+8))
#define const_uint(X1) const_word(X1,0) | const_word(X1,16)
#define const_switch_word(X1, X2) (is_const(X1) ? const_word(X1,0) : X2)
#define const_switch_uint(X1, X2) (is_const(X1) ? const_uint(X1) : X2)
const int X1 = 222;
const int X2 = printf("") + 333;
char Y1[ const_switch_word(X1,256) ];
char Y2[ const_switch_word(X2,256) ];
template< int N >
void test(int N1) {
char _buf[N>0?N:1];
char* buf = _buf;
if(N==0) {
buf = new char[N1];
}
printf("%08X %3i %3i\n", buf, N, N1);
}
#define testwrap(N) test< const_switch_word(N,0) >(N)
int main(void) {
printf("%i %i %i\n", X1, is_const(X1), sizeof(Y1));
printf("%i %i %i\n", X2, is_const(X2), sizeof(Y2));
testwrap(X1);
testwrap(X2);
}
'is_const()' funziona per x> = 0 solo, ma il trucco (fare un risultato a tempo di compilazione non definito) lavora con 'is_const (X) | is_const (-X) 'anche, avendo quindi is_const che lavora solo per' all x: x! = INT_MIN'. –
Nota che 'sizeof (int)' e 'sizeof (char)' non sono garantiti per essere diversi (e ci sono processori di vita reale dove sono gli stessi), quindi dovresti usare qualcosa come 'char [2]'. (D'altra parte, vedo costanti hardcoded quindi suppongo che la portabilità non sia un problema.) – ymett
Grande codice, ottima idea (suppongo che la fonte originale sia http://encode.ru/threads/396-C-compile-time Constant-rilevamento?). Ho adattato il codice is_const ad essere un po 'più portatili (problemi sizeof char, INT_MAX utilizzato), per gestire tutti i possibili valori di input, e ha creato una versione più semplice non-gcc - vedi http://stackoverflow.com/questions/7658060/ can-i-use-assume-hint-to-elide-a-call-if-an-edge-condition-is-known-at-compile/7658363 # 7658363 – Suma