There is a way in gcc to get a warning when a constexpr can't be evaluated at compile time?

684 views Asked by At

I'm using gcc 5.1.0 (c++14) and I was trying with constexpr. Is very annoying to verify if the constexpr I've implemented are evaluated at compile time. I couldn't find any flag for get a warning about that situation.

Here is an example: example.cpp -----------------------------------------

#include <stdlib.h>

const char pruVar[] = "12345678901234567";


[[gnu::noinline]] constexpr unsigned int myStrlen(const char* cstr)
{
    unsigned int i=0;
    for(;cstr[i]!=0;++i);
    return i; 
}

struct CEXAMPLE
{
    unsigned int size;
    constexpr CEXAMPLE(const char* s): size(myStrlen(s))
    {
    }
};

int main(void)
{
    CEXAMPLE c(pruVar);
    unsigned int size = myStrlen(pruVar);
    void* a = malloc(c.size + size);
    if (a != nullptr)
        return 0;
    else
        return 1;
}

In the example CEXAMPLE::CEXAMPLE is evaluated at compile time including the call to myStrlen in it, but the call to myStrlen in main is being evaluated at runtime. The only way I have to know this is looking at the assembler.This website is very useful too: http://gcc.godbolt.org/

If you know how to make the compiler warn about this or something similar I'll appreciate it

2

There are 2 answers

0
ecatmur On BEST ANSWER

myStrlen(pruVar) can be evaluated at compile time; the compiler is just choosing not to in this instance.

If you want to force the compiler to evaluate it at compile time or error if this is not possible, assign the result to a constexpr variable:

constexpr unsigned int size = myStrlen(pruVar);
^^^^^^^^^

You could also use an enum, or a std::integral_constant:

enum : unsigned int { size = myStrlen(pruVar) };
std::integral_constant<unsigned int, myStrlen(pruVar)> size;
0
Alexander On

Based on the fact that template arguments must be evaluated at compiletime a helper template can be used.

namespace helper {
template<class T, T v> constexpr T enforce_compiletime() {
    constexpr T cv = v;
    return cv;
}
}

#define compiletime(arg) ::helper::enforce_compiletime<decltype(arg), (arg)>()

This allows compile time enforcement without an additional constexpr variable, which is handy in order to calculate value lookup tables.

constexpr uint32_t bla(uint8_t blub) {
    switch (blub) {
        case 5:
            return 22;
        default:
            return 23;
    }
}

struct SomeStruct {
    uint32_t a;
    uint32_t b;
};

SomeStruct aStruct = {compiletime(bla(5)), compiletime(bla(6))};