Время компиляции C++ постоянное обнаружение

Существуют случаи, когда источник библиотеки доступен, и он должен поддерживать переменные параметры в целом, но на практике эти параметры обычно являются константами.

Затем может быть возможно оптимизировать вещи специальной обработкой постоянных параметров (например, использовать статические массивы вместо выделения "кучи"), но для этого его необходимое, чтобы определить, является ли что-то первой константой (или возможно определяют некоторые макросы, но его менее удобное).

Таким образом, вот рабочая реализация.

Обновление: также здесь: http://codepad.org/ngP7Kt1V

  1. Это - действительно допустимый C++?
  2. Существует ли способ избавиться от них макросы? (is_const () не может быть функция, потому что функциональная зависимость не будет работать в выражении размера массива; также это не может быть шаблон, потому что это не примет переменный параметр также.)

Обновление: вот обновление с чем-то больше как намеченное использование. Компилятор не сгенерирует кода для if(N==0) ответвление, если N не 0. Тем же путем мы можем переключиться на совершенно другие структуры данных, если мы хотим. Уверенный не прекрасный, но вот почему я отправил этот вопрос.


 #include 

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(char))
#define is_const(X) is_const_0( (X)^((X)&0x7FFFFFFF) )

#define const_bit(X1,bit) (is_const_0i((X1)&(1< 
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 );
}

9
задан bpeterson76 11 December 2012 в 20:52
поделиться

3 ответа

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 () позже. Я понятия не имею, как реализовать другой способ, трюк деконструировать / реконструировать великолепен.

1
ответ дан 5 December 2019 в 01:42
поделиться

Если вы можете передать параметр шаблона, то он гарантированно будет 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.

0
ответ дан 5 December 2019 в 01:42
поделиться

Если вы работаете с GCC, используйте __ builtin_constant_p , чтобы узнать, является ли что-то постоянной времени компиляции. В документации есть такие примеры, как

static const int table[] = {
  __builtin_constant_p (EXPRESSION) ? (EXPRESSION) : -1,
  /* ... */
};
2
ответ дан 5 December 2019 в 01:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: