2015-04-28 5 views
1

Возможно ли передать исходный стол функции по значению? Я считаю, что это невозможно, но я ищу официальные источники, чтобы это подтвердить.Таблица pass по значению


Я знаю, как передать таблицу по ссылке:

template<typename T, size_t N, size_t M> 
void first_example(T (&table_in_function)[N][M]) { 
    //... 
} 
//... 
int a[50][20]; 
//... 
first_example(a); 

или std::array, но, как я грустный, я ищу решение для сырых таблиц. Простая идея, удалите &, очевидно, неправильно. Также я не ищу что-то вроде:

template<typename T, size_t N, size_t M> 
void third_example(T (&temp_ref)[N][M]) { 
    T local_table[N][M]; 
    //... 
} 

Я принимаю решения, такие как магический код и мета-программирование.

+3

Из-за устаревшего ограничения (из-за C) невозможно иметь параметры массива верхнего уровня. Вместо этого вы должны использовать что-то вроде 'std :: array'. (Или оберните его в свой собственный класс/структуру). – Rufflewind

+2

@ Rufflewind: Пожалуйста, опубликуйте ответы как _answers_. –

+0

@ Rufflewind Это то, чего я ожидал. (Просто мало надежды, что это возможно.) Однако я не видел официальных источников, чтобы это доказать. Спасибо за ваш комментарий. :) – Tacet

ответ

2

Невозможно объявить параметр функции для типа массива. В частности, C++ стандарт (§8.3.5/5) указует:

После определения типа каждого параметра, любой параметра типа «массив Т» или «функция, возвращающая T» корректируется, чтобы быть «указатель to T "или" указатель на функцию возврата T "соответственно.

Итак, если вы попытаетесь создать функцию с параметром с типом массива, этот параметр будет «скорректирован» компилятором, чтобы вместо этого стать указателем.

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

1

Это невозможно. Маски C-стиля автоматически распадаются на указатели при передаче в функцию.

Вам придется явно скопировать массив.

2

Канонический способ обработки этого : использовать std::array (или эквивалентный тип обертки).

Кроме того, вы не повезло, потому что C++ запрещает прямое копирование инициализацию массивов:

[C++11: 8.5/16]:[..] Семантика инициализаторах заключаются в следующем. Тип назначения является типом инициализированного объекта или ссылки, а тип источника является типом выражения инициализатора. Если инициализатор не является одним (возможно, в скобках) выражением, тип источника не определен.

  • Если инициализатор представляет собой (не в скобках) приготовился-INIT-лист, объект или ссылка список инициализируется (8.5.4).
  • Если тип назначения является ссылочным типом, см. 8.5.3.
  • Если тип назначения - это массив символов, массив char16_t, массив char32_t или массив wchar_t, а инициализатор - строковый литерал, см. 8.5.2.
  • Если инициализатор равен (), объект инициализируется значением.
  • В противном случае, если тип назначения является массивом, программа плохо сформирована. [..]

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

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

+0

Поэтому я заметил, что это вопрос синтаксического сахара. Я знаю, как нормально справляться с этой проблемой. – Tacet

+0

@Tacet 'std :: array' не совсем синтаксический сахар, он, вероятно, реализован как шаблонный массив, хранящийся внутри' struct'. Тогда конструктор копии по умолчанию 'struct' скопирует элементы при передаче по значению. – vsoftco

+0

@Tacet: Я не уверен, что «синтаксический сахар» означает то, что вы думаете, что это значит. Несмотря на это, я поддерживаю этот ответ. Если вы не хотите передавать по ссылке или передавать как указатель, или обертывать что-то вроде 'std :: array' ... то вы ничего не можете сделать. Вот и все. –

Смежные вопросы