简体   繁体   English

C ++编译时常量检测

[英]C++ compile-time constant detection

There're cases when a library source is available, and it has to support variable parameters in general, but in practice these parameters are commonly constants. 存在库源可用的情况,并且它通常必须支持变量参数,但实际上这些参数通常是常量。

Then it may be possible to optimize things by special handling of constant parameters (eg. use static arrays instead of heap allocation), but for that its necessary to determine whether something is a constant first (or maybe define some macros, but its less convenient). 然后可以通过对常量参数的特殊处理来优化事物(例如,使用静态数组而不是堆分配),但为此必须首先确定某些事物是否是常量(或者可能定义一些宏,但它不太方便)。

So here's a working implementation. 所以这是一个有效的实现。

Update: also here: http://codepad.org/ngP7Kt1V 更新:也在这里: http//codepad.org/ngP7Kt1V

  1. Is it really a valid C++ ? 它真的是一个有效的C ++吗?
  2. Is there a way to get rid of these macros? 有没有办法摆脱这些宏? (is_const() can't be a function because the function dependence won't work in array size expression; also it can't be a template because that won't accept a variable parameter either. ) (is_const()不能是函数,因为函数依赖在数组大小表达式中不起作用;它也不能是模板,因为它也不接受变量参数。)

Update: Here's an update with something more like intended usage. 更新:这是一个更符合预期用途的更新。 The compiler won't generate any code for the if(N==0) branch if N is not 0. Same way we can switch to completely different data structures if we want. 如果N不为0,编译器将不会为if(N==0)分支生成任何代码。 if(N==0)我们可以切换到完全不同的数据结构。 Sure its not perfect, but that's why I posted this question. 当然它不完美,但这就是我发布这个问题的原因。


 #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 ); }

If you're working with GCC, use __builtin_constant_p to tell you whether something is a compile time constant. 如果您正在使用GCC,请使用__builtin_constant_p告诉您某些内容是否为编译时常量。 The documentation includes examples like 该文档包括例如

static const int table[] = {
  __builtin_constant_p (EXPRESSION) ? (EXPRESSION) : -1,
  /* ... */
};

is_const should be more reliable. is_const应该更可靠。 On gcc-4.4 for example, the following: 例如,在gcc-4.4上,以下内容:

int k=0;
printf("%d\n",is_const(k),is_const(k>0));

prints: 打印:

0,1

GCC is quite ambitious folding constant expressions which are not integral constant expressions by the words of the standard. GCC是一个非常雄心勃勃的折叠常量表达式,它不是标准单词的整数常量表达式。 A potentially better definition of is_const could be: 可能更好的is_const定义可能是:

#define is_const(B)\
(sizeof(chkconst::chk2(0+!!(B))) != sizeof(chkconst::chk2(0+!(B))))

Aside from that, your technique is awesome, because I can finally write a SUPER_ASSERT macro which is checked during compilation if the assertion expression if compile-time and during runtime otherwise: 除此之外,你的技术很棒,因为我最终可以编写一个SUPER_ASSERT宏,如果编译时在编译时检查断言表达式,那么在运行时也是如此:

#define SUPER_ASSERT(X) {BOOST_STATIC_ASSERT(const_switch_uint(X,1));assert(X);}

I'll look into that const_switch_xxx() thing later. 我稍后会研究那个const_switch_xxx()的事情。 I have no idea how to implement another way, the deconstruct/reconstruct trick is brilliant. 我不知道如何实现另一种方式,解构/重构技巧是辉煌的。

If you can pass in a template parameter then it is guaranteed to be a constexpr (the Standard's term for compile-time expressions). 如果你可以传入一个模板参数,那么它保证是一个constexpr(标准的编译时表达式术语)。 If it's not passed by template parameter, then it's not a constexpr. 如果它没有通过模板参数传递,那么它不是constexpr。 There is no way around this. 没有办法解决这个问题。

What would be much easier is to hand-roll a stack allocated variable length array class using alloca. 更容易的是使用alloca手动滚动堆栈分配的可变长度数组类。 This will guarantee stack allocation for arrays, regardless of whether or not they're static or not. 这将保证数组的堆栈分配,无论它们是否是静态的。 In addition, you can get much of the same iteration functionality of a vector/boost::array. 此外,您可以获得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];
            }
        };

Note that I haven't actually tested this code, but it would be MUCH easier to grab, use, and maintain than to maintain that monstrosity in your OP. 请注意,我实际上没有测试过这段代码,但抓取,使用和维护比在OP中维护那些怪物要容易得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM