2017-01-11 4 views
3

В следующем примере я использую static_assert для проверки того, что foo определяется во время компиляции. Проходит static_assert, и я проверил с неправильным условием, что он фактически активен. Это означает, что во время компиляции известно foo. Но если я пройду через код с отладчиком, я вижу, что skip_first_word также выполняется во время выполнения.const char * constexpr оценивается во время компиляции и во время выполнения

// Skip the first word in p_str 
constexpr const char * skip_first_word(const char * p_str) { 
    return (*p_str == '\0') ? p_str : 
     (*p_str == ' ') ? p_str + 1 : 
     skip_first_word(p_str + 1); 
} 

// constexpr to calculate the length of a string 
constexpr size_t str_len(const char * p_str) { 
    return (*p_str == '\0') ? 0 : str_len(p_str + 1) + 1; 
} 

int main() 
{ 
    constexpr auto foo = skip_first_word("Hello, World!"); 
    constexpr auto foo_size = str_len(foo); 
    static_assert(foo_size == 6, "Wrong size"); 

    // This assert successfully fails 
    // static_assert(foo_size == 7, "Wrong size"); 

    // Prevent optimizations 
    for(auto ptr = foo; *ptr != '\0'; ++ptr) { 
     volatile auto sink = ptr; 
    } 
    volatile auto sink = &foo_size; 

    return 0; 
} 

Что здесь происходит? Почему во время выполнения нельзя использовать foo, который был рассчитан во время компиляции?

Edit: Такое поведение наблюдается с Visual Studio 2015

+0

Вы использовали тот же уровень оптимизации в обоих случаях, верно? –

+0

@ n.caillou Да, я запускал оба случая с оптимизацией и без них. –

+0

@ FrançoisAndrieux: обновил мой ответ, чтобы осветить поведение VS2015 –

ответ

5

gcc.godbolt.org показывает, что ваш код полностью оптимизирован с обеих НКУ 7 и лязг 3.9, используя -std=c++11 -O1 флаги.

Несовершенствование операций volatile будет, очевидно, сгенерировать инструкции по сборке, но инструкции для skip_first_word или str_len не генерируются.


Вы правы относительно Visual Studio: использование CL 19 on gcc.beta.godbolt.org показывает, что сборка генерируется для:

constexpr auto foo = skip_first_word("Hello, World!"); 
constexpr auto foo_size = str_len(foo); 

Это похоже на дефект реализации компилятора, поскольку constexpr переменные могут и должны быть полностью вычислен во время компиляции. Кроме того, переменные используются внутри static_assert, который равен , который может быть оценен во время компиляции. Это, по-видимому, предполагает, что компилятор без необходимости генерирует сборку для skip_first_word и str_len, даже несмотря на то, что они никогда не используются во временном контексте.

вручную встраивание кода следующим образом ...

static_assert(str_len(skip_first_word("Hello, World!")) == 6, "Wrong size"); 
static_assert(str_len(skip_first_word("Hello, World!")) != 7, "Wrong size"); 

...produces no extra assembly.