1369 / 592 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
1

Двумерный массив <array>. const int value = array.size(); value не константа?

14.05.2016, 16:15. Показов 5533. Ответов 36
Метки нет (Все метки)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <array>
#include <iostream>
 
using std::array;
using std::cout;
 
/*ФУНКЦИЯ ЗАПОЛНЕНИЯ МАССИВА ЗНАЧЕНИЯМИ*/
template <typename T>
void arr_init(T& arr, int count = 0){
    for (auto &i:arr){
        for (auto &j:i){
            j = count++;
        }
    }
}
 
/*ФУНКЦИЯ ВЫВОДА МАССИВА НА ЭКРАН*/
template <typename T>
void arr_show(T& arr){
    for (const auto &i:arr){
        for (const auto &j:i){
            cout << j << '\t';
        }   cout << '\n';
    }
}
 
/*ФУНКЦИЯ ПЕРЕМЕШИВАЕТ СТРОКИ*/
template <typename T>
void shuffle_row(T& arr){
    const int ROW = arr.size();
    array<T,ROW> temp;  //<-- Где я что-то не понял?
}
 
 
int main(){
    array<array<int,9>,10> arr;
 
    arr_init(arr);
    arr_show(arr);
    shuffle_row(arr);
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
14.05.2016, 16:15
Ответы с готовыми решениями:

Преобразовать указатель на int array в int array
Через SendMessage передаю указатель на int массив: int m_list; ::SendMessage((HWND)hwnd,...

Расстановка девяти чисел (Turbo C) Выводит ошибку using Matrix = std::array<std::array<int, 3>, 3>; и bool NextSet
#include &lt;iostream&gt; #include &lt;array&gt; using Matrix = std::array&lt;std::array&lt;int, 3&gt;, 3&gt;; //...

Присвоить значения переменных в массив Array (class Array в Turbo C++)
Здравствуйте!!! Изучаю help в Turbo C++ 3.1 дошел до класса Array: main() { //при ...

SIZE of array is not computable
мой код: open (666, file = &quot;debug.txt&quot;) write(666,*) 'begin' DO i=1,size(x) write(666,*) x(i) ...

36
Evg
Эксперт CАвтор FAQ
21265 / 8281 / 637
Регистрация: 30.03.2009
Сообщений: 22,638
Записей в блоге: 30
14.05.2016, 16:27 2
const означает не "константа", а "немодифицируемый (неизменный)"
1
1369 / 592 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
14.05.2016, 17:19  [ТС] 3
Я предпочту увидеть ответ на заданный вопрос. Пример не компилируется, почему?

Добавлено через 30 минут
Всё. Вспомнил. Ответ не нужен.
0
Вездепух
Эксперт CЭксперт С++
10818 / 5840 / 1584
Регистрация: 18.10.2014
Сообщений: 14,493
14.05.2016, 19:33 4
Цитата Сообщение от daslex Посмотреть сообщение
Пример не компилируется, почему?
Пример не компилируется потому, что в языке С++ целочисленное const значение является Целочисленным Константным Выражением тогда и только тогда, когда его инициализатор является Целочисленным Константным Выражением.

В вашем случае ROW инициализировано при помощи вызова constexpr метода std::array<>::size() через ссылку. Методы, вызванные через ссылку, не порождают Целочисленного Константного Выражения, даже если эти методы являются constexpr.
1
1369 / 592 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
14.05.2016, 19:52  [ТС] 5
В моём случае: то, что я в ROW пихаю, неизвестно на этапе компиляции;
Вот и всё.
0
Вездепух
Эксперт CЭксперт С++
10818 / 5840 / 1584
Регистрация: 18.10.2014
Сообщений: 14,493
14.05.2016, 20:19 6
Цитата Сообщение от daslex Посмотреть сообщение
В моём случае: то, что я в ROW пихаю, неизвестно на этапе компиляции;
Ну это было бы слишком просто. Это вы фактически перефразировали сообщение об ошибке.

Сразу надо заметить, что ваш оригинальный код прекрасно компилируется gcc

http://coliru.stacked-crooked.... 4ad15dc04f

А вот clang выдает ошибку

http://coliru.stacked-crooked.... 3a33d6f578

То есть вопрос несколько неоднозначный.

Метод std::array<>::size() является constexpr, причем его результат напрямую определяется шаблонным параметром. Т.е. теоретически это значение прекрасно известно на этапе компиляции и теоретически у компилятора есть все необходимое для того, чтобы вычислить это constexpr именно как constexpr, т.е. именно на этапе компиляции. Что gcc и делает.

Для clang, похоже, преградой тут является именно вызов constexpr метода через ссылку. Если в вашем примере убрать ссылку с объявления параметра, то пример начнет прекрасно компилироваться и в clang.

А вот как правильно - надо разбираться...
2
1369 / 592 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
14.05.2016, 21:11  [ТС] 7
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Сразу надо заметить, что ваш оригинальный код прекрасно компилируется gcc
Ну, не эксперт я, я - чайник.

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

В общем, правильно как в clang, а оптимизации эти - это оптимизации.

Добавлено через 3 минуты
Если надо разбираться, я как бы не против.

Добавлено через 41 минуту
Студия так пишет:
Ошибка C2971 std::array: параметр шаблона "_Size": ROW: переменная с нестатической длительностью хранения не может использоваться в качестве аргумента, не являющегося типом
0
Вездепух
Эксперт CЭксперт С++
10818 / 5840 / 1584
Регистрация: 18.10.2014
Сообщений: 14,493
14.05.2016, 21:13 8
Цитата Сообщение от daslex Посмотреть сообщение
Некоторые компиляторы при оптимизациях иногда умеют вычислять то, что предполагается константой ещё до выполнения. То есть фактически это так и выглядит, что вроде должно быть неизвестно, но как по мановению волшебной палочки почему-то известным становится ещё до компиляции. Как-то так.
Такая логика применима именно и только к оптимизациям - то есть к контекстам, в которых формально безразлично, будет ли значение вычислено на этапе компиляции или на этапе выполнения. Это чисто количественный вопрос, ибо такие контексты не влияют на корректность (то есть компилируемость) программы.

Когда же речь заходит о таких принципиальных качественных вопросах, как формирование Целочисленных Константных Выражений, т.е. решениях, влияющих на компилируемость кода, то тут спецификация языка никакой свободы компиляторам не предоставляет. Контексты, в которых const и constexpr обязаны порождать Целочисленные Константные Выражения (т.е. порождать значения, известные на стадии компиляции), оговорены однозначно.

Вопрос в данном случае только в том, относится ли данный случай к набору таких контекстов.
2
Evg
Эксперт CАвтор FAQ
21265 / 8281 / 637
Регистрация: 30.03.2009
Сообщений: 22,638
Записей в блоге: 30
14.05.2016, 21:31 9
Сдаётся мне, если есть два массива

C++
array<int,10> a;
array<int,20> b;
 
shuffle_row(a);
shuffle_row(b);
то инстанциация шаблоной функции shuffle_row становится невозможной, потому что невозможно будет правильно задать шаблон для массива temp. Т.е. должны будут одновременно существовать две реализации shuffle_row<int> с различными типами temp. Поэтому по хорошему такой код компилятору следует запрещать
1
1369 / 592 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
14.05.2016, 21:47  [ТС] 10
Цитата Сообщение от Evg Посмотреть сообщение
то инстанциация шаблоной функции shuffle_row становится невозможной
Ну gcc считает возможной, я на сайте том же проверил, на который тут сослано.
Хотя по логике возможным быть не должно.

Добавлено через 4 минуты
Коли о ссылках рассуждать, то я бы и о && не хотел забывать. Там тоже как с &.
0
Вездепух
Эксперт CЭксперт С++
10818 / 5840 / 1584
Регистрация: 18.10.2014
Сообщений: 14,493
14.05.2016, 22:06 11
Цитата Сообщение от Evg Посмотреть сообщение
то инстанциация шаблоной функции shuffle_row становится невозможной, потому что невозможно будет правильно задать шаблон для массива temp.
В смысле? С точки зрения классической инстанциации shuffle_row<T>, array<int,10> и array<int,20> - это два совершенно разных, совершенно независисмых типа Т. Поэтому в данном примере будет инстанциироваться две отдельных, ничего друг о друге не знающих специализации функции shuffle_row: скажем shuffle_row_std_array_int_10 и shuffle_row_std_array_int_20. В каждой будет свой массив temp и никаких неоднозначностей с его размером не будет.

Цитата Сообщение от Evg Посмотреть сообщение
Т.е. должны будут одновременно существовать две реализации shuffle_row<int> с различными типами temp.
В этом коде нет shuffle_row<int>. В этом коде инстанциируется именно shuffle_row<std::array<...>>, а это совсем другая история.


Цитата Сообщение от Evg Посмотреть сообщение
Поэтому по хорошему такой код компилятору следует запрещать
Это зачем это его запрещать? Это фундаметальная функциональность шаблонов. А уж то, что автор кода применил ее именно так - это вопрос к автору кода.
1
Evg
Эксперт CАвтор FAQ
21265 / 8281 / 637
Регистрация: 30.03.2009
Сообщений: 22,638
Записей в блоге: 30
14.05.2016, 22:38 12
Чота под вечер я тупить начал
0
1369 / 592 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
14.05.2016, 23:03  [ТС] 13
Итак, обсуждаем теперь

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <array>
#include <iostream>
 
using std::array;
using std::cout;
 
 
template <class T>
void foo1(T& arr) {
    constexpr int ROW = arr.size();
}
 
template <class T>
void foo1(T&& arr) {
    constexpr int ROW = arr.size();
}
 
 
int main() {
    array<array<int, 9>, 10> arr = {};
    //foo1(arr);  //<-- Пока не напишу, претензий не имеется
    //foo2(arr);
}
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
18.05.2016, 01:37 14
daslex, я не спец как вот hoggy может вам ответить , но вроде бы ответ очевиден - ссылка это абстрактная сущность времени выполнении: для взятия размера нужен объект (дяда с адрессом, который оживает только вовремя выполнения)
0
1369 / 592 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
18.05.2016, 01:43  [ТС] 15
А без ссылки не абстрактная сущность времени выполнения?
0
Эксперт С++
8720 / 4300 / 958
Регистрация: 15.11.2014
Сообщений: 9,744
18.05.2016, 02:09 16
Цитата Сообщение от daslex Посмотреть сообщение
const int ROW = arr.size();
* * array<T,ROW> temp; *//<-- Где я что-то не понял?
error C2971: std::array: параметр шаблона "_Size": ROW: локальная переменная не может использоваться в качестве аргумента, не являющегося типом
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
ссылка это абстрактная сущность времени выполнении
1.
ссылки - псевдонимы имен объектов.
а компиляторы замечательно умеют различать объекты
по их именам.

2.
ссылки могут быть использованы в качестве параметров шаблона.

3.
к конкретно данной ситуации (#13) ссылки не имеют ни малейшего отношения.
код валидный, и успешно собирается компиляторами,
которые поддерживают constexpr.

проблема с компиляторами студии: они до сих пор его не осилили.
0
Вездепух
Эксперт CЭксперт С++
10818 / 5840 / 1584
Регистрация: 18.10.2014
Сообщений: 14,493
18.05.2016, 02:18 17
Цитата Сообщение от hoggy Посмотреть сообщение
код валидный, и успешно собирается компиляторами,
которые поддерживают constexpr.
Как уже говорилось выше, код НЕ собирается clang - ошибка в обоих функциях одна и та же

Код
clang -std=c++14 -pedantic-errors main.cpp

main.cpp:10:25: error: constexpr variable 'ROW' must be initialized by a constant expression
    constexpr int ROW = arr.size();
                        ^~~~~~~~~~
main.cpp:15:25: error: constexpr variable 'ROW' must be initialized by a constant expression
    constexpr int ROW = arr.size();
                        ^~~~~~~~~~
Clang, разумеется, поддерживает constexpr, однако не считает arr.size() константным выражением, пока вызов делается через ссылку.
0
Эксперт С++
8720 / 4300 / 958
Регистрация: 15.11.2014
Сообщений: 9,744
18.05.2016, 02:45 18
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Как уже говорилось выше, код НЕ собирается clang - ошибка в обоих функциях одна и та же
значит он так же не осилил constexpr

Добавлено через 3 минуты
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Clang, разумеется, поддерживает constexpr, однако не считает arr.size() константным выражением, пока вызов делается через ссылку.
я понял.
0
Вездепух
Эксперт CЭксперт С++
10818 / 5840 / 1584
Регистрация: 18.10.2014
Сообщений: 14,493
18.05.2016, 03:15 19
Цитата Сообщение от hoggy Посмотреть сообщение
значит он так же не осилил constexpr
Нет, как раз таки в данном случае похоже, что это именно GCC позволяет себе слишком много и/или пытается бежать впереди паровоза.

Добавлено через 12 минут
А именно, согласно цитате, которую мне подсказали на StackOverflow, core constant expression e не должно содержать вычисления

- an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
-- it is initialized with a constant expression or
-- its lifetime began within the evaluation of e;
Именно это требование нарушено в данном случае. Прав именно clang.
1
1369 / 592 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
24.05.2016, 21:16  [ТС] 20
Я тут немного подумал, так как словечки выше какие-то заморские, непонятные, и вот что решил:
В параметрах функции не может быть constexpr, поэтому оно и не интерпретируется как константа
В случае локальной копии
C++
1
2
3
4
template <class T>
void foo1(T arr) {
    constexpr int ROW = arr.size();
}
Получается что-то вида
C++
1
2
3
4
5
void foo(){
   size_t temp = arr.size(); //данные по arr тут известны и вычисляемо на этапе компиляции
   constexpr int ROW = temp; //constexpr вне параметров функции
   T arr[temp]; //Вне параметров функции, ну а тип Т известен, всё на этапе компиляции
}
А в случаях
C++
1
2
void foo1(T& arr)
void foo1(T&& arr)
Вычисление arr.size(); попадает вовнутрь параметров функции, а не в её тело. Только один нюанс мешает, constexpr в параметры функции всовывать непозволительно

========================
Я может где немного неправильно выразился, но суть должна быть понятна. Если так рассуждать, то как-то легко всё встаёт на свои места и напрашивается вывод на глюк в тексте предупреждения.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.05.2016, 21:16
Помогаю со студенческими работами здесь

Array with unknown size
Имеется некий текстовый массив: string arr = new string Допустим, что хотя бы цифру m мы знаем...

Delphi. Двумерный массив. Заполнить массив А следующим образом var A:array [1.10, 1.10] of byte; :
Помогите решить задачу, как заполнить ее в StringGrid var A:array of byte; Заполнить массив...

Переписать программу через класс Array (двумерный массив).
Помогите написать вот эту программу через класс Array(двумерный массив) using System; using...

Двумерный массив std::array. Размеры массива шаблоном
#include &lt;array&gt; #include &lt;iostream&gt; using std::array; using std::cout; template &lt;typename...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru