LINUX.ORG.RU

[C++] почему?

 


0

0
void f(const int[3]);

...

f({1, 2, 3});

почему так нельзя? при том, что вот так:

const int a[3] = {1, 2, 3};

f(a);

вполне себе законно. {} - это, вроде бы, конструктор для const T[]; конструкторы в вызове функции использовать вполне себе можно. основание для такого особого отношения есть вообще?

это всё при том, что:

void g(const char[3]);

...

g("123");

замечательно работает. C-style строка в C++ - она, в общем-то, массив символов - два исключения из общих языковых правил в одном выражении

ну и то, что и в f и в g можно с лёгкостью передавать массивы большего размера, чем указано в сигнатуре, тоже как-то нехорошо. приведение T[] к T* это, конечно, не так уж и плохо - но толку тогда от такой сигнатуры, спрашивается, если компилятор (с -Wall -pedantic) даже предупреждения не выдаёт?

★★★★★
Ответ на: комментарий от jtootf

>такое же, как и при встрече "12", с той лишь разницей, что в данном случае у нас массив не char[], а int[]

Откуда компилятор знает, что это не char[] ?

golodranez ★★★★
()
Ответ на: комментарий от jtootf

> с той лишь разницей, что в данном случае у нас массив не char[], а int[]

А кто сказал, что именно int[]? Где объявление типа?

LamerOk ★★★★★
()
Ответ на: комментарий от golodranez

>Откуда компилятор знает, что это не char[] ?

на основании стандарта ISO/IEC 14882. правила приведения типов в выражениях, содержащих числовые литералы, там написаны чёрным по белому

jtootf ★★★★★
() автор топика
Ответ на: комментарий от LamerOk

>А кто сказал, что именно int[]? Где объявление типа?

ну твою же дивизию. а в выражении int a = 1 где справа объявление типа? в друг это short? а вдруг char?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от LamerOk

>существует иллюзия, будто бы литерял является выражением

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

jtootf ★★★★★
() автор топика
Ответ на: комментарий от golodranez

>Пока да, но уже сейчас инициализация вроде "char *str = "asdf";" - deprecated.

ох ты. а что взамен?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

> а в выражении int a = 1 где справа объявление типа? в друг это short? а вдруг char?

Справа его нет и не должно быть. Литерал будет будет приведен к типу lvalue. Ты же пытаешься использовать литерал без объявления типа.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

>Справа его нет и не должно быть. Литерал будет будет приведен к типу lvalue

а в выражении f(1) при f ~ void f(int)? тут к чему будет приведён литерал?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

>на основании стандарта ISO/IEC 14882. правила приведения типов в выражениях, содержащих числовые литералы, там написаны чёрным по белому

Т.е. по твоему char a = 1; будет ошибкой? :))

golodranez ★★★★
()
Ответ на: комментарий от jtootf

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

Разумеется. Об этом и речь. Ты пытаешься использовать литера как выражение, чего делать нельзя, и о чем тебе не двусысленно намекает компилятор, пытающийся распарсить выражение и обнаруживший его не корркетным.

Дубль 2 - литерал не есть выражение.

LamerOk ★★★★★
()
Ответ на: комментарий от jtootf

> а в выражении f(1) при f ~ void f(int)? тут к чему будет приведён литерал?

К объявленному типу первого аргумента f(..)

LamerOk ★★★★★
()
Ответ на: комментарий от jtootf

>"12" - похоже, а {1, 2} - не похоже? вся информация для выполнения такого действия у компилятора есть, в чём проблема?

Наверное массив это не единственный составной тип. Структуры тоже можно передавать по указателю и инициализировать списком значений в фигурных скобочках. BTW, есть еще немного запутанные правила поиска подходящего темплейта функции по сигнатуре которые видимо немного рискованно запутывать еще больше.

Absurd ★★★
()
Ответ на: комментарий от golodranez

>Т.е. по твоему char a = 1; будет ошибкой? :))

нет. в том-то и дело

jtootf ★★★★★
() автор топика
Ответ на: комментарий от LamerOk

>Ты пытаешься использовать литера как выражение

я пытаюсь использовать литерал как литерал

jtootf ★★★★★
() автор топика
Ответ на: комментарий от LamerOk

>К объявленному типу первого аргумента f(..)

ну вот и чудесно. у меня функция f имеет тип void f(int[3]). в чём проблема передать в неё {1, 2, 3}?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от Absurd

>Наверное массив это не единственный составной тип

да, похоже что беда именно в этом -. различить инициализаторы составных типов компилятор не может

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

>>невозможности четко определить правила преобразования compound-дитерала

>поясни.

{ 1, 2, 3} можно считать int[3] или short[3], unsigned по вкусу. А, насколько я понимаю, тип в Си++ должен быть очевиден из изображения самого литерала (тип, указанный в прототипе функции, рассматривается только как целевой тип преобразования типов). Поэтому работает (int[3]){1,2,3}.

> я вижу проблему только с неоднозначностью определения {}, которые используются почём зря

Тоже достаточная причина.

tailgunner ★★★★★
()
Ответ на: комментарий от jtootf

>ох ты. а что взамен?

Я щас в венде, а гуглить лень:) Но один из последних GCC выдавал мне сообщение о deprecated. И мне это кажется вполне логичным. Т.е. делая char *a = "sdf"; у нас "на вид" происходит присвоение литерала указателю, что не вполне прозрачно, согласись?

Взамен я думаю будет предложенно пользоваться стандартным malloc + stncpy = что выглядит хоть и более громоздко, но зато прозрачно.

golodranez ★★★★
()
Ответ на: комментарий от tailgunner

>Поэтому работает (int[3]){1,2,3}.

не работает, error: ISO C++ forbids compound-literals

>{1, 2, 3} можно считать int[3] или short[3], unsigned по вкусу

в случае передачи его в функцию, принимающую int[3], компилятор имеет полное право считать его int[3] точно так же, как в случае передачи в функцию, принимающую short, 1 будет иметь тип short

jtootf ★★★★★
() автор топика
Ответ на: комментарий от golodranez

>у нас "на вид" происходит присвоение литерала указателю, что не вполне прозрачно, согласись?

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

>Взамен я думаю будет предложенно пользоваться стандартным malloc + stncpy

грустно

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

>>Ты пытаешься использовать литера как выражение

> я пытаюсь использовать литерал как литерал


И где?

>>К объявленному типу первого аргумента f(..)


> ну вот и чудесно. у меня функция f имеет тип void f(int[3]). в чём проблема передать в неё {1, 2, 3}?


Что передать? Твоя функция принимает указатель на массив. Где указатель?

Ты не втыкаешь, что литералы - это константы, существующие только на этапе компиляции. На этапе исполнения их нет.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

>Ты не втыкаешь, что литералы - это константы, существующие только на этапе компиляции. На этапе исполнения их нет.

щито? и во что же они превращаются, если не секрет? литерал "123", например?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от golodranez

> Но один из последних GCC выдавал мне сообщение о deprecated. И мне это кажется вполне логичным. Т.е. делая char *a = "sdf"; у нас "на вид" происходит присвоение литерала указателю, что не вполне прозрачно, согласись?

> Взамен я думаю будет предложенно пользоваться стандартным malloc + stncpy = что выглядит хоть и более громоздко, но зато прозрачно.


Не болтай ерундой, а пиши правильно:

const char *a = "sdf";

LamerOk ★★★★★
()
Ответ на: комментарий от tailgunner

вообще круто, конечно. передать в функцию, имеющую тип void (bool) строку ("123", например) - без проблем, а вот передать в функцию, имеющую тип void (int[3]) массив вида {1, 2, 3} - нельзя

jtootf ★★★★★
() автор топика
Ответ на: комментарий от golodranez

> > "12" - похоже, а {1, 2} - не похоже?
> Пока да, но уже сейчас инициализация вроде "char *str = "asdf";" - deprecated.
Ты прескорбно туп. Как можно объявить указатель char * на char[5] const?
Поэтому компилятор и требует char const *str = "asdf";

l5k
()
Ответ на: комментарий от l5k

ну, в контексте задачи это несущественно. понятно, что указатель на константные данные

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

Поэтому работает (int[3]){1,2,3}.

не работает

void ff(int[3]);

void f()
{
        ff((int[3]){1,2,3});
}
[vmg@xarn2 tmp]$ gcc --version
gcc (Debian 4.3.2-1.1) 4.3.2
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
tailgunner ★★★★★
()
Ответ на: комментарий от jtootf

> и? предлагаешь добавить квалификатор const? так он проблемы не решает

Нет, я предлагаю тебе честно _объявить массив_, если он тебе действительно нужен, а потом уже пытаться взять от него адрес. Взять адрес у несуществующего массива реально трудно.

LamerOk ★★★★★
()
Ответ на: комментарий от jtootf

>грустно

я не помню, касаеться это только pure C или С++. В любом случае в С++ есть string.

у кого под рукой новые версии gcc. Скомпильте код типа int main(){char *a = "string";} сперва gcc, потом g++. Что он там выдаёт?

golodranez ★★★★
()

>{} - это, вроде бы, конструктор для const T[];

Это не конструктор, он не создаёт объект, только инициализирует существующий, причём он может быть и не константой. Так что тип объекта неизвестен, он автоматически не создаётся.

>C-style строка в C++ - она, в общем-то, массив символов

константный массив, размешается в другом сегменте памяти. его тип известен.

P.S. лучше бы про многомерные массивы спрашивал.

anonymous
()
Ответ на: комментарий от LamerOk

>Не болтай ерундой, а пиши правильно: const char *a = "sdf";

Думаешь в этом причина? Хотя логично:) И всётаки скомпильте ктонить код int main(){char *a = "string"; const char *b = "string";}

golodranez ★★★★
()
Ответ на: комментарий от tailgunner

всё работает, только тип должен быть константой. не константы на стеке автоматически не создаются.

anonymous
()
Ответ на: комментарий от LamerOk

>Взять адрес у несуществующего массива реально трудно.

и с какой радости он несуществующий? я там выше уже написал - засунули массив в сегмент данных и получили константный на него указатель. никакой магии

jtootf ★★★★★
() автор топика
Ответ на: комментарий от anonymous

>константный массив, размешается в другом сегменте памяти. его тип известен.

а у {1, 2, 3} размер неизвестен, или он неконстантен?

>Это не конструктор, он не создаёт объект, только инициализирует существующий

тем не менее при явном объявлении типа в более новом чем мой g++ это работает

jtootf ★★★★★
() автор топика

А вообще, по топику видно, что хаскелисты, либо математики особого профиля( которых исчезающе мало), либо монадодрочеры, которым кажется крутым делать сайды эффекты через одно место и постоянно рефакторить свои классы типов.

anonymous
()
Ответ на: комментарий от LamerOk

>Взять адрес у несуществующего массива реально трудно.

Он вполне себе существует в рантайме в секции .const вместе с другими литералами.

Absurd ★★★
()
Ответ на: комментарий от golodranez

>У меня возник такой вопрос - а нафиг оно вообще может понадобиться это f({1, 2, 3})?

затем же, зачем может понадобится вызов вида f("some text"). на самом деле в практическом смысле особого профита нет, просто интересно стало

jtootf ★★★★★
() автор топика
Ответ на: комментарий от golodranez

>У меня возник такой вопрос - а нафиг оно вообще может понадобиться это f({1, 2, 3})?

В каком-нибудь препроцессоре может наверно быть кстати чтобы с уникальными именами символов не трахаться.

Absurd ★★★
()
Ответ на: комментарий от jtootf

>а у {1, 2, 3} размер неизвестен, или он неконстантен?

кстати, размер только мешает. он может инициализировать и не константы.

>тем не менее при явном объявлении типа в более новом чем мой g++ это работает

если это про int a[] = {1,2,3}, то это не объявление. это создание массива.

anonymous
()
Ответ на: комментарий от anonymous

>если это про int a[] = {1,2,3}, то это не объявление. это создание массива.

про f((int[3]){1, 2, 3})

jtootf ★★★★★
() автор топика
Ответ на: комментарий от anonymous

>всё работает, только тип должен быть константой. не константы на стеке автоматически не создаются.

хотя может дело в гцц.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.