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) даже предупреждения не выдаёт?

★★★★★

Вот так. Это тебе не лисп.

alex4
()

Зачем кстати это надо? Лень лишние переменные заводить под аргументы функции? Можно сделать что-нибудь вроде

{
int temp_array[3] = {var1, var2, var3};
func(temp_array);
}

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

>Зачем кстати это надо?

это неправильный вопрос. правильный вопрос - почему этого нельзя? меня не очень интересует практическая сторона, меня интересуют соображения, по которым этой возможности в C++ нет

>Можно сделать что-нибудь вроде

можно. я даже в исходном сообщении потрудился об этом написать

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

да, и ещё пусть мне кто-нибудь расскажет, почему вот так тоже нельзя:

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

при том, что вот так можно:

const int a[2][3] = {{0}};
jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

почему этого нельзя?

Потому, что массив нельзя использовать как литерал вне формы инициализации, как и любой другой не примитивный тип (по крайней мере в языке C). Так ведь понятнее?

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

А что он пишет, если попытаться скомпилировать этот пример?

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

>Потому, что массив нельзя использовать как литерал вне формы инициализации, как и любой другой не примитивный тип

чем строка "123" существенно отличается от массива char a[3] = {'1', '2', '3'}? иными словами, ответа я не вижу - да, нельзя. а почему нельзя?

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

>все нормально работает

таки работает. ладно, этот вопрос снимается :)

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

«123» это значение простого типа, а {'1', '2', '3'} составного. Больше никакой разницы нет. Очевидно или сложилось исторически или для читаемости. Что такое принимает f в

f("124", 4, "12")
понятно, а в
f({"124", {4, "12"}})
не очень.

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

Вообще в последнем стандарте C такая штука есть. В C++ врядли.

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

>"123" это значение простого типа, а {'1', '2', '3'} составного

можно уточнить типы? я разницы по-прежнему не вижу

>не очень

ну ясное дело, у тебя там ill-formed массив - {4, "12"} быть не может, ибо у 4 и "12" типы как раз разные

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

можно уточнить типы? я разницы по-прежнему не вижу

Массив может содержать в себе другие массивы, а строка нет. Определение(bnf) составного типа рекурсивно.

ill-formed массив

Точно. Я о структурах думал.

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

>Массив может содержать в себе другие массивы, а строка нет. Определение(bnf) составного типа рекурсивно.

грамматическое определение, опять же, неинтересно. семантически, строка - это char[]; строковый литерал имеет тип const char[] соответствующей размерности. разницы на уровне _типов_ - нет. если есть возражения, прошу (повторно) объявить типы для строки и для массива char'ов, чтобы можно было их сравнить

>строка нет

собственно, ответа это всё равно не даёт. да, массив обладает свойством замыкания,- и как это препятствует такому вот его созданию?

складывается впечатление, что грамматика C++ местами не дружит с его же семантикой

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

А можно так?

template <typename T>
void fn(T const &t)
{
  // do something with t
}

enum {
  kInt,
  kString
} type = kString;

fn( type == kString ? "привет, начинки для гробов"
  : type == kInt    ? 123
  : assert("в type-e говно какое-то", false));
Короче говоря, реализовать алгебраические типы.

l5k
()

void f(const int[3]); f({1, 2, 3});

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

Нет там никакого конструктора. {} - это инициализатор массива, используется только для инициализации.

при том, что вот так: const int a[3] = {1, 2, 3}; f(a); вполне себе законно

Законно, да.

это всё при том, что: void g(const char[3]); g(«123»);

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

«123» - строковый литерал, const char[n+1]. Неявно приводится к char*.

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

Массивы в функцию передаются только по указателю со всеми последствиями.

Может стоит литературу почитать?

Loronymous
()

то чем аффтар возмущается , для меня довольно естественно
видимо , потому , что я лиспа не знаю

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

> видимо , потому , что я лиспа не знаю

Хаскеля же.

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

> 1, 2, 3 - они какого типа? short, int? unsigned?

А если еще и union забабахать? Тогда совсем "у-у-у".

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

а при чем тут?

Возмущения автора как раз таки только к статически-типизированным языкам применимы. И в данном случае - в сравнении с хаскелем.

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

Да, нет. Массивы можно ведь создавать на стеке и передавать по указателю.

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

>Массивы в функцию передаются только по указателю со всеми последствиями.

может, поспорим?

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

{} - это инициализатор массива, используется только для инициализации

ок. объясни мне, будь добр, чем инициализатор отличается от конструктора

template <typename T>
T h()
{
    T obj();

    return obj;
}

и что используется в данном случае

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

>1, 2, 3 - они какого типа? short, int? unsigned?

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

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

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

>И в данном случае - в сравнении с хаскелем.

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

jtootf ★★★★★
() автор топика
Ответ на: комментарий от beastie
f((const int[3]){1,2,3});

error: ISO C++ forbids compound-literals

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

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

Тебе уже объяснили, что конструкция которую ты хочешь использовать применяется ТОЛЬКО при инициализации массива, а "some_text" - это строковой литерал. Так что там про неоднородность?

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

>так почему же нельзя функцию типа int[2] вызвать как f({1, 2})?

Ты должен передать в функцию указатель на массив. Где он? {1, 2} - не очень похоже на указатель.

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

>конструкция которую ты хочешь использовать применяется ТОЛЬКО при инициализации массива

вот я и хочу узнать - почему. на этот вопрос никто так и не ответил

>Так что там про неоднородность?

интересно, а если в стандарте будет принято писать объявления перменных исключительно таким int a = tin(3) образом - что, все хором тоже дружно скажем "так надо"?

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

>Ты должен передать в функцию указатель на массив

ок, не вопрос

>{1, 2} - не очень похоже на указатель.

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

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

собственно, вопрос можно сократить - почему C++ forbids compound-literals? и почему сообщение о подобной ошибке можно получить, только явно прописав тип этого самого литерала (в противном случае сообщение есть только о синтаксической ошибке)?

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

>> 1, 2, 3 - они какого типа? short, int? unsigned?

> о правилах приведения типов для числовых литералов в стандарте написано вполне себе ясно

Но тут числовые литералы надо привести к типу массива.

> если бы проблема была в этом, она была бы чуть более заметна - не находишь?

Я думаю, из-за этого (невозможности четко определить правила преобразования compound-дитерала) в стандарте и нет такого преобразования.

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

Очевидно же, крестофилия и ебланство - одинаковые по сути вещи.

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

>Но тут числовые литералы надо привести к типу массива.

ну вот ещё. числовые литералы нужно привести к числу. к int, например (по стандарту именно так компилятор в данном случае и должен поступить); а затем уже можно разобрать compound literal, проверить чтобы все типы совпадали и привести к const int[literal_size]

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

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

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

>Вот с этого и надо начинать.

да нет, не столь это существенно на самом деле. достаточно трактовать инициализатор как составной литерал

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

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

Какого "такого"? Какое действие должен выполнить компилятор, встретив литерал {1,2}?

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

>Какое действие должен выполнить компилятор, встретив литерал {1,2}?

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

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

> достаточно трактовать инициализатор как составной литерал

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

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