A: 

I hope it's self-explaining

struct TrueType {};
struct FalseType {};
template<class T>
struct IsConst
{
    typedef FalseType Result;
};
template<class T>
struct IsConst<const T>
{
    typedef TrueType Result;
};

//now, const/non-const specific code
template<class T>
void func(T t)
{
    //dispatching call to the appropriate implementation
    doFunc(t, (IsConst<T>::Result*)NULL);
}
template<class T>
void doFunc(T t, TrueType*)
{
    std::cout << "func implementation for constants";
}
template<class T>
void doFunc(T t, FalseType*)
{
    std::cout << "func implementation for not constants";
}
//usage
    int a = 6;
    const int b = 5;
    func(a);
    func(b);

You also need a specialization of IsConst template for const pointers, though.

However it's not working for calls with values (like "func(5);")

Alsk
Or you can use the to-become-standard is_const http://msdn.microsoft.com/en-us/library/bb982361.aspx
Tomaka17
That's not what the OP wants. There's a difference between a const and a compile time const.
Luther Blissett
The problem is that (afaik) this would apply also in thecase like `const int tmp = printf("");` but you won't beable to declare an array of size `tmp`. Otherwise I'd just use boost::is_const or something
Shelwien
Anyway you can't optimize anything ; here you can write "char Y1[X1]" because the value of X1 is known at compile time, but if you write a function in a library the only way to know an array size at compile-time is to use template<int>
Tomaka17
@Shelwien: So, as I understand it, we have to detect whether the symbol passed to the library is a constant or a variable. But could you provide example how one can use the library, what is the method of passing that symbol to the library?
Alsk
@Alsk: Is this better? (I edited the question)Btw, the code you've posted is interesting too, though isn't really an "answer" :)
Shelwien
@Shelwien: yes, now it's clear, but I would reformulate the task as preprocessor-time detection :)
Alsk
The detection itself is compile-time. But I do hope that there's a way to reduce the amount of macros. Specifically, I'd really appreciate a non-bitwise implementation of `is_const(X) ? X : 0`.
Shelwien
@Alsk: No, its compile-time - but there is a difference between `const` integrals (which don't necessarily have to be known at compile-time) and *integral constant expressions* (which is what the OP wants). The latter can e.g. used as array-sizes and to initialize static const integral class-members, the former not.
Georg Fritzsche
A: 

If you can pass in a template parameter then it is guaranteed to be a constexpr (the Standard's term for compile-time expressions). If it's not passed by template parameter, then it's not a 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. 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.

        #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.

DeadMG
Well, my code implements a way to pass a function of (possible) variable as a template parameter. Also this is not really about allocating tables on stack, but about switching to an optimized library version when it appears that (maybe some of) parameters are known at compile time.
Shelwien
@Shelwien: It's true that your code has some potential that mine doesn't. However, my code also has a lot of potential that yours doesn't.
DeadMG
Sure, thanks for sharing your code, but imho its not really related to the topic :)
Shelwien
@Shelwien: It solves the actual problem that you posted (static vs dynamic allocation of a potentially runtime determinant size). I just produced a different (much better) implementation with a different backing idea as to how to accomplish it.
DeadMG
-1: The OP does **not** want to solve some variable length arrays on the stack problem. He showed us a method to detect during compile time, if a value is a constexpr **and a ingenious way to craft a constexpr to select a constexpr depeding on constexpr'ness of another value**. You people should understand what that means, before you upvote anything. The value of const_switch_uint can be used anywhere, where a constant integral value is required, for example template non-type parameters, enum definitions, switch statement case labels...
Luther Blissett
@Luther: No, you should learn to read. He says himself that you can't perform this trick with function parameters, thus solving exactly nothing. The statement in my OP is entirely true- constexpr values to function parameters do not produce a constexpr argument. The OP will have to separately provide both template and runtime argument versions of any library that wishes to support this. If he wants to use a user-provided int to instantiate templates, he is going to have to either start including user-defined headers, or taking them by template. His macros do not solve that problem.
DeadMG
@Luther Blissett: Agreed, though the magic in the implementation is too evil for me :) trying to find simpler way, since it is proved that it's possible
Alsk
@DeadMG: or any library function would have the same int argument in two forms - the template argument form and usual function argument and every call would be wrapped in macro as it is already illustrated by Shelwien
Alsk
A: 

is_const should be more reliable. On gcc-4.4 for example, the following:

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. A potentially better definition of is_const could be:

#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:

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

I'll look into that const_switch_xxx() thing later. I have no idea how to implement another way, the deconstruct/reconstruct trick is brilliant.

Luther Blissett
Its even trickier. For example, afair, with `gcc -O0` `is_const(x)` would return 0 for `const int x=0;`. But I think its good enough if it doesn't misdetect a variable as constant.
Shelwien
Isn't this actually a violation of the standard by gcc? I can't find any wording that would permit it to interpret eg. `k-k` (where `k` is a variable of type `unsigned int`) as an integral constant-expression and hence as a null-pointer constant, even though it always evaluates to zero.
jpalecek
+1  A: 

If you're working with GCC, use __builtin_constant_p to tell you whether something is a compile time constant. The documentation includes examples like

static const int table[] = {
  __builtin_constant_p (EXPRESSION) ? (EXPRESSION) : -1,
  /* ... */
};
0x4b
I tried that, but its different, same as corresponding boost template - my example doesn't work if I redefine is_const 0 and is_const_0i using that builtin - const_switch* results are wrong and the template example doesn't compile at all. Also I need it to be compatible with MSC and IntelC anyway, beside gcc.
Shelwien