2014-08-31 3 views
8

Я написал функцию constexpr, которая возвращает массив.constexpr возвращающий массив, gcc warning

#include <iostream> 

constexpr auto get_str(void) 
-> const char(&)[4] { 
    return { 'T', 'E', 'S', 'T' }; 
} 

constexpr int sum(const char(&str)[4]){ 
    return str[0] + str[1] + str[2] + str[3]; 
} 

int main(void){ 

    constexpr int s = sum(get_str()); 

    std::cout << s << std::endl; 

    return 0; 
} 

г ++ 4.8 компилирует код правильно, но выдает следующее предупреждение:

test.cpp: In function ‘constexpr const char (& get_str())[4]’: 
test.cpp:5:30: warning: returning reference to temporary [-Wreturn-local-addr] 
    return { 'T', 'E', 'S', 'T' }; 

ли предупреждение правильным в такой ситуации? Неправильно ли возвращать массив из такой функции constexpr, даже если функция никогда не вызывается во время выполнения, только во время компиляции?

+1

Вы можете использовать 'станд :: массив ', чтобы вернуть статический массив constexpr по значению, вместо того, чтобы возвращать ссылку. –

+0

@MikaelPersson Спасибо, я попытался использовать std :: array в какой-то момент, но мой полный код выполняет некоторые странные вещи, которые требуют преобразования времени компиляции в const char *, и я не мог сделать & arr [0] в константе выражение. – Xeno

ответ

2

clang 3.4 не компилирует этот код, так как sum(get_str()) не constexpr и, насколько я могу сказать clang правильно здесь, эта линия (see it live):

constexpr int s = sum(get_str()); 

генерирует следующее сообщение об ошибке:

error: constexpr variable 's' must be initialized by a constant expression 
constexpr int s = sum(get_str()); 
      ^ ~~~~~~~~~~~~~~ 

note: read of temporary whose lifetime has ended 
return str[0] + str[1] + str[2] + str[3] 
    ^

Недействительный constexpr по двум причинам. Это вызывает неопределенное поведение, и это explicitly disallowed in a constant expression, обобщать the draft C++ standard раздел 5.19 говорит:

A conditional-expression e is a core constant expression unless the evaluation of e,

и содержит следующую пулю:

an operation that would have undefined behavior

который доступ вне его жизни будет. Мы знаем, что время жизни временно не распространяется в данном случае из раздела 12.2Временных объектов который говорит:

The second context is when a reference is bound to a temporary.117 The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except

и включает в себя следующую пулю:

The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.

Так что, хотя это действительно так, что a константное выражение не может быть оценено при переводе, мы имеем примечание в разделе 5.19Константные выражения, которые упоминают это (курсив мой идти вперед):

Note: Constant expressions can be evaluated during translation.—end note ]

Даже если это было гарантировано мы все еще не будет позволено вызвать неопределенное поведение.

Второй вопрос заключается в том, что constexpr ссылки должны быть либо к объектам статической продолжительности хранения или функций, cppreference упоминает об этом в своем core constant expression section:

Reference constant expression is an lvalue core constant expression that designates an object with static storage duration or a function

и, насколько я могу сказать, что это рассматривается в разделе 5.19Постоянные выражения пункт который говорит:

each non-static data member of reference type refers to an object with static storage duration or to a function,

1

the function is never actually called at runtime, only during compilation?

Не гарантируется на всех по стандарту. Компилятор находится в пределах своих прав, чтобы вызвать его во время выполнения.

constexpr временно не умирает если компилятор вызывает его во время компиляции. Компилятор не несет никаких обязательств.

+0

Это не было никаких обязательств, но он определенно сделал это во время компиляции, глядя на сборку. Я предполагаю, что это предупреждение оправдано, и если это не будет гарантировано, я избегу этого. – Xeno

+0

Я знаю, что это устарело, но я видел это в другом вопросе, и здесь уместно: «Помимо возможности оценивать выражения во время компиляции, мы хотим, чтобы ** требовать выражения, которые должны оцениваться во время компиляции; constexpr перед определением переменной делает ** (и подразумевает const): " – Xeno