9

ライブラリ ソースが利用可能で、一般に変数パラメーターをサポートする必要がある場合がありますが、実際には、これらのパラメーターは一般的に定数です。

次に、定数パラメーターの特別な処理 (たとえば、ヒープ割り当ての代わりに静的配列を使用) によって物事を最適化できる可能性がありますが、そのためには、最初に何かが定数であるかどうかを判断する必要があります (または、いくつかのマクロを定義することもできますが、あまり便利ではありません)。 )。

これが実用的な実装です。

更新: こちらも: http://codepad.org/ngP7Kt1V

  1. 本当に有効な C++ ですか?
  2. これらのマクロを取り除く方法はありますか? ( is_const() は、関数の依存関係が配列サイズの式で機能しないため、関数にすることはできません。また、変数パラメーターも受け入れないため、テンプレートにすることもできません。)

更新:これは、意図された使用法に似た更新です。if(N==0)が 0 でない場合、コンパイラは分岐のコードを生成しませNん。同様に、必要に応じて完全に異なるデータ構造に切り替えることができます。確かに完璧ではありませんが、それがこの質問を投稿した理由です。


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

3 に答える 3

2

GCCを使用__builtin_constant_pしている場合は、を使用して、コンパイル時定数であるかどうかを確認します。ドキュメントには、次のような例が含まれています

static const int table[] = {
  __builtin_constant_p (EXPRESSION) ? (EXPRESSION) : -1,
  /* ... */
};
于 2010-08-04T22:16:40.147 に答える
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() については後で調べます。別の方法を実装する方法がわかりません。分解/再構築のトリックは素晴らしいです。

于 2010-07-21T16:48:56.020 に答える
0

テンプレート パラメーターを渡すことができる場合、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 でその怪物を維持するよりも、取得、使用、および維持する方がはるかに簡単です。

于 2010-07-21T15:27:22.050 に答える