Значения по умолчанию для аргументов массива
Просто немного поиграйте с С++. То, что я действительно хочу сделать, - это настроить функцию со значениями по умолчанию, определенными для аргумента массива или указателя. Чтобы все было просто, позвольте просто использовать массив. Например:
void experimentA(char a[3] = {'a', 'b', 'c'});
Компилятор (LLVM GCC 4.2 с GNU99) жалуется на "Ожидаемое выражение". Это довольно тупо, но мне сказали коллеги, что это происходит потому, что "ценность", которую я пытаюсь назначить, статически распределяется, тогда как переменная, которую я пытаюсь назначить (a[3]
), авто.
Но я не совсем уверен, если это так, поскольку я могу это сделать:
void experimentB(char a[3] = "abc");
И компилятор просто предупреждает меня, что преобразование string-literal в char * устарело.
Я не понимаю, как "abc" принципиально отличается от {'a', 'b', 'c'}, чтобы вызвать это несоответствие. Любое понимание очень ценится!
Ответы
Ответ 1
Ваши коллеги ошибаются или, может быть, вас неправильно поняли.
Первый ключ к пониманию заключается в том, что вы не можете иметь массив как параметр функции в C или С++. Причины исторические. Поэтому, когда вы пишете void experimentA(char a[3] ...)
, компилятор автоматически преобразует его в указатель, т.е. void experimentA(char* a ...)
. Поэтому реальный вопрос в том, почему "abc"
является подходящим значением по умолчанию для a и { 'a', 'b', 'c' }
. Причина в том, что компилятор объясняет: "abc"
- выражение, а { 'a', 'b', 'c' }
- нет (его инициализатор). Есть несколько мест на С++, где вы можете использовать инициализатор и некоторые, где вы не можете. Значение по умолчанию для параметра просто является одним из мест, которые вы не можете.
Ответ 2
Когда вы используете строковый литерал "abc", он выделяется компилятором где-то в памяти, а указатель на его первый символ используется как значение по умолчанию. Итак, для компилятора код такой: void experimentA(char a[3] = 0x12345678);
.
Во втором случае литерал массива не выделяется компилятором в виде строки (что я бы рассматривал как некоторую несогласованность в языке).
Ответ 3
"abc"
- это выражение. Бывает, что он ведет себя особенно, отличным от всех других выражений, когда он используется для инициализации переменной типа array of char
.
{'a','b','c'}
не является выражением, а инициализатором. Это только синтаксически разрешено в определениях переменных. Там синтаксис допускает либо выражение, либо инициализатор без выражения, но это не означает, что инициализаторы могут использоваться как выражения где-либо еще.
Ответ 4
"abc"
является выражением, {'a', 'b', 'c'}
является статическим инициализатором. Более поздняя версия разрешена только в объявлениях переменных. По неизвестным мне причинам аргумент со значением по умолчанию имеет другое правило грамматики, которое не позволяет статические инициализаторы.
Есть некоторые существенные изменения, когда статические инициализаторы разрешены в С++ 0x, но я не уверен, как это влияет на рассматриваемый случай.
Ответ 5
Параметр по умолчанию должен быть действительным.
Вы можете позвонить
F ( "ABC" )
но никогда
F ({ 'а', 'б', 'с'});
"abc" фактически является адресом в памяти, а {'a', 'b', 'c'} означает инициализацию массива или struct/class.
Ответ 6
Один простой способ сделать это - перегрузка старой старой функции. Например, ниже имитируется значение параметра по умолчанию для параметра формата, которое char * type:
static string to_string(time_point<system_clock> time)
{
return to_string(time, "%Y-%m-%d-%H-%M-%S");
}
static string to_string(time_point<system_clock> time, const char* format)
{
time_t tt = system_clock::to_time_t(time);
char str[1024];
if (std::strftime(str, sizeof(str), format, std::localtime(&tt)))
return string(str);
else return string();
}