[英]What is the best way in C++ to have a compile-time constant depend on a type's size?
[英]C++ compile-time constant detection
存在庫源可用的情況,並且它通常必須支持變量參數,但實際上這些參數通常是常量。
然后可以通過對常量參數的特殊處理來優化事物(例如,使用靜態數組而不是堆分配),但為此必須首先確定某些事物是否是常量(或者可能定義一些宏,但它不太方便)。
所以這是一個有效的實現。
更新:也在這里: http : //codepad.org/ngP7Kt1V
更新:這是一個更符合預期用途的更新。 如果N
不為0,編譯器將不會為if(N==0)
分支生成任何代碼。 if(N==0)
我們可以切換到完全不同的數據結構。 當然它不完美,但這就是我發布這個問題的原因。
#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 );
}
如果您正在使用GCC,請使用__builtin_constant_p
告訴您某些內容是否為編譯時常量。 該文檔包括例如
static const int table[] = {
__builtin_constant_p (EXPRESSION) ? (EXPRESSION) : -1,
/* ... */
};
is_const應該更可靠。 例如,在gcc-4.4上,以下內容:
int k=0;
printf("%d\n",is_const(k),is_const(k>0));
打印:
0,1
GCC是一個非常雄心勃勃的折疊常量表達式,它不是標准單詞的整數常量表達式。 可能更好的is_const定義可能是:
#define is_const(B)\
(sizeof(chkconst::chk2(0+!!(B))) != sizeof(chkconst::chk2(0+!(B))))
除此之外,你的技術很棒,因為我最終可以編寫一個SUPER_ASSERT宏,如果編譯時在編譯時檢查斷言表達式,那么在運行時也是如此:
#define SUPER_ASSERT(X) {BOOST_STATIC_ASSERT(const_switch_uint(X,1));assert(X);}
我稍后會研究那個const_switch_xxx()的事情。 我不知道如何實現另一種方式,解構/重構技巧是輝煌的。
如果你可以傳入一個模板參數,那么它保證是一個constexpr(標准的編譯時表達式術語)。 如果它沒有通過模板參數傳遞,那么它不是constexpr。 沒有辦法解決這個問題。
更容易的是使用alloca手動滾動堆棧分配的可變長度數組類。 這將保證數組的堆棧分配,無論它們是否是靜態的。 此外,您可以獲得vector / boost :: array的大部分相同迭代功能。
#define MAKE_VLA(type, identifier, size) VLA< (type) > identifier ( alloca( (size) * sizeof ( type ) ), (size) );
template<typename T> class VLA {
int count;
T* memory;
VLA(const VLA& other);
public:
// Types
typedef T* pointer;
typedef T& reference;
typedef const T* const_pointer;
typedef const T& const_reference;
typedef T value_type;
typedef std::size_t size_type;
class iterator {
mutable T* ptr;
iterator(T* newptr)
: ptr(newptr) {}
public:
iterator(const iterator& ref)
: ptr(ref.ptr) {}
operator pointer() { return ptr; }
operator const pointer() const { return ptr; }
reference operator*() { return *ptr; }
const reference operator*() const { return *ptr; }
pointer operator->() { return ptr; }
const pointer operator->() const { return ptr; }
iterator& operator=(const iterator& other) const {
ptr = iterator.ptr;
}
bool operator==(const iterator& other) {
return ptr == other.ptr;
}
bool operator!=(const iterator& other) {
return ptr != other.ptr;
}
iterator& operator++() const {
ptr++;
return *this;
}
iterator operator++(int) const {
iterator retval(ptr);
ptr++;
return retval;
}
iterator& operator--() const {
ptr--;
return *this;
}
iterator operator--(int) const {
iterator retval(ptr);
ptr--;
return retval;
}
iterator operator+(int x) const {
return iterator(&ptr[x]);
}
iterator operator-(int x) const {
return iterator(&ptr[-x]);
}
};
typedef const iterator const_iterator;
class reverse_iterator {
mutable T* ptr;
reverse_iterator(T* newptr)
: ptr(newptr) {}
public:
reverse_iterator(const reverse_iterator& ref)
: ptr(ref.ptr) {}
operator pointer() { return ptr; }
operator const pointer() const { return ptr; }
reference operator*() { return *ptr; }
const reference operator*() const { return *ptr; }
pointer operator->() { return ptr; }
const pointer operator->() const { return ptr; }
reverse_iterator& operator=(const reverse_iterator& other) const {
ptr = reverse_iterator.ptr;
}
bool operator==(const reverse_iterator& other) {
return ptr == other.ptr;
}
bool operator!=(const reverse_iterator& other) {
return ptr != other.ptr;
}
reverse_iterator& operator++() const {
ptr--;
return *this;
}
reverse_iterator operator++(int) const {
reverse_iterator retval(ptr);
ptr--;
return retval;
}
reverse_iterator& operator--() const {
ptr++;
return *this;
}
reverse_iterator operator--(int) const {
reverse_iterator retval(ptr);
ptr++;
return retval;
}
reverse_iterator operator+(int x) const {
return reverse_iterator(&ptr[-x]);
}
reverse_iterator operator-(int x) const {
return reverse_iterator(&ptr[x]);
}
};
typedef const reverse_iterator const_reverse_iterator;
typedef unsigned int difference_type;
// Functions
~VLA() {
for(int i = 0; i < count; i++)
memory[i].~T();
}
VLA(void* stackmemory, int size)
: memory((T*)stackmemory), count(size) {
for(int i = 0; i < count; i++)
new (&memory[i]) T();
}
reference at(size_type pos) {
return (reference)memory[pos];
}
const_reference at(size_type pos) {
return (const reference)memory[pos];
}
reference back() {
return (reference)memory[count - 1];
}
const_reference back() const {
return (const reference)memory[count - 1];
}
iterator begin() {
return iterator(memory);
}
const_iterator begin() const {
return iterator(memory);
}
const_iterator cbegin() const {
return begin();
}
const_iterator cend() const {
return end();
}
const_reverse_iterator crbegin() const {
return rbegin();
}
const_reverse_iterator crend() const {
return rend();
}
pointer data() {
return memory;
}
const_pointer data() const {
return memory;
}
iterator end() {
return iterator(&memory[count]);
}
const_iterator end() const {
return iterator(&memory[count]);
}
reference front() {
return memory[0];
}
const_reference front() const {
return memory[0];
}
reverse_iterator rbegin() {
return reverse_iterator(&memory[count - 1]);
}
const_reverse_iterator rbegin() const {
return const_reverse_iterator(&memory[count - 1]);
}
reverse_iterator rend() {
return reverse_iterator(memory[-1]);
}
const_reverse_iterator rend() const {
return reverse_iterator(memory[-1]);
}
size_type size() {
return count;
}
reference operator[](int index) {
return memory[index];
}
const reference operator[](int index) const {
return memory[index];
}
};
請注意,我實際上沒有測試過這段代碼,但抓取,使用和維護比在OP中維護那些怪物要容易得多。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.