2016-11-12 2 views
0

Я пытаюсь понять, что вижу, проверяя изменения. Платформа - openSUSE 42 с GCC 4.8, но это может повлиять на других. Затем следует тестовый код и ошибка.Почему я должен использовать const с constexpr для статической функции класса?

$ cat test.cxx 
#include <string> 

#if (__cplusplus >= 201103L) 
# define STATIC_CONSTEXPR static constexpr 
# define CONSTEXPR constexpr 
#else 
# define STATIC_CONSTEXPR static const 
# define CONSTEXPR 
#endif 

struct Name 
{ 
    STATIC_CONSTEXPR char* GetName() {return "XXX";} 
}; 

int main(int argc, char* arv[]) 
{ 
    const char* name = Name::GetName(); 
    return 0; 
} 

И:

$ g++ -O3 -std=c++11 test.cxx -o test.exe 
test.cxx: In static member function ‘static constexpr char* Name::GetName()’: 
test.cxx:13:44: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings] 
    STATIC_CONSTEXPR char* GetName() {return "XXX";} 
              ^

Добавление следующих не ясно, что:

struct Name 
{ 
    STATIC_CONSTEXPR char* const GetName() {return "XXX";} 
}; 

И добавив следующий делает ясно, что:

struct Name 
{ 
    STATIC_CONSTEXPR const char* GetName() {return "XXX";} 
}; 

По Does static constexpr variable make sense?:

Каждая переменная объявлена ​​constexpr неявно Const, но сопзЬ и статические почти ортогональны

Я думал, что я в основном (для взаимодействия со статическими константных чисел, за исключением.) понял constexpr, но я, очевидно, что-то пропустил (снова). Насколько я понимаю, комитет C++ считает, что значение, подобное "XXX" в проигрывателе, может как-то измениться после сохранения файла, даже если оно невозможно по законам физической вселенной, как мы их понимаем в настоящее время. Однако, чтобы бороться с проблемой, они дали нам constexpr. Альтернативное объяснение - here, но я должен признать, что я не вижу более тонких деталей, которые делают разницу.

Почему я вижу предупреждение, и почему я действительно нуждаюсь в static constepr const, чтобы раздавить его?


$ uname -a 
Linux opensuse-42 4.1.27-27-default #1 SMP PREEMPT Fri Jul 15 12:46:41 UTC 2016 (84ae57e) x86_64 x86_64 x86_64 GNU/Linux 
opensuse-42:~$ gcc -v 
Using built-in specs. 
COLLECT_GCC=gcc 
COLLECT_LTO_WRAPPER=/usr/lib64/gcc/x86_64-suse-linux/4.8/lto-wrapper 
Target: x86_64-suse-linux 
Configured with: ../configure --prefix=/usr ... --host=x86_64-suse-linux 
Thread model: posix 
gcc version 4.8.5 (SUSE Linux) 
+4

Нет, вы не понимаете проблему. «значение, подобное« XXX »в проигрывателе, может как-то измениться после сохранения файла» - это бессмысленное утверждение, которое не имеет к этому никакого отношения. Литеральная константа строки, «XXX» - это 'const char *', и ваш неудачный код пытается вернуть его как 'char *'. Указатель на постоянный объект не может быть преобразован в указатель на изменяемый объект, неявно. Это не имеет никакого отношения к 'constexpr'. –

+0

Вы назначаете 'const char *', поэтому ваша функция должна возвращать 'const char *'. – Galik

+0

Итак, я понятен ... Значение, возвращаемое из статической функции, помеченной как constexpr, не является неявным 'const'. Это верно? Это вызывает вопрос, если вместо функции function должно быть '... Name() {STATIC_CONSTEXPR char val [] =" XXX "; return val; } '? – jww

ответ

8

constexpr на объявлении функции означает, что функция constexpr, а не ее тип возвращаемого значения.

Так что ваша проблема на самом деле сводится к тому, следующий синтаксис является неправильным:

char * foo = "bar"; 

Поскольку C++ 11 это преобразование из char const[] в char* утончаются незаконно, и является устаревшим, так как C++ 98.

Исследуется указатель const, в отличие от указателя на константу. here.

Итак, чтобы вернуть строковый литерал, вам необходимо использовать char const*. static и constexpr не связаны с этой проблемой.

+0

Простите мое невежество ... Что представляет собой пример переменной или возвращаемого значения функции, помеченной как 'contexpr', но разрешенной как неконстантная? I.e., вызывающий может изменить его. Это не имеет никакого смысла для меня; они кажутся ортогональными. – jww

+1

@jww Вы также можете использовать функцию 'constexpr' в непостоянных контекстах. Вот почему, вероятно, было принято решение, что функции 'constexpr' не должны возвращать' const' по умолчанию. И даже если бы они вернули 'const', в вашем случае сам указатель был бы' const' (например, 'char * const'), а не данные, на которые он указывает (' char const * '). – vsoftco

+0

Спасибо @krzaq. Итак, C++ 11 хочет 'static constexpr char * constexpr Name()'? Внешняя говорит, что функция не изменится после сохранения файла; а внутренний говорит, что данные в массиве не будут меняться после сохранения файла? – jww

3

Литератор строк "..." имеет тип const char[], т. Е. Массив символов const. Он может разлагаться до const char*, если необходимо.

Вы получаете предупреждение, потому что используете устаревшее преобразование от const char* до char*/char* const.Не имеет значения, что функция constexpr, она применима только к самой функции, а не к возвращаемому значению. Не имеет смысла указывать constexpr на возвращаемое значение, потому что оно либо уже constexpr из-за функции, либо нет.

Таким образом, ваш код эквивалентен записи

char* return_value = "XXX"; 
char* const return_value = "XXX"; 

Поскольку ни один из этих указателей не указывают на const char, вы получите предупреждение.

2

constexpr не имеет к этому никакого отношения.

char *foo() { return "ABC"; } 

даст такое же предупреждение. "ABC" является строковым литералом и имеет тип const char[4] (массив из четырех постоянных символов). Как и любой другой массив, он легко распадается на указатель типа char const * (указатель на постоянный символ).

Для строковых литералов (только), есть также Устаревшее преобразование в char * (указатель на неконстантных полукокса) - то есть то, что ваша функция используется, и это то, что GCC не нравится. Исправление либо:

char const *foo() ... 

или (что эквивалентно)

const char *foo() ...