Подтвердить что ты не робот

Значения по умолчанию для аргументов массива

Просто немного поиграйте с С++. То, что я действительно хочу сделать, - это настроить функцию со значениями по умолчанию, определенными для аргумента массива или указателя. Чтобы все было просто, позвольте просто использовать массив. Например:

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'}, чтобы вызвать это несоответствие. Любое понимание очень ценится!

4b9b3361

Ответ 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();
}