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

Как Страуструп принимает неконстантную ссылку на временную?

В книге программирования языка программирования Stroustrup С++ (3-е издание) в главе Numerics он показывает следующий фрагмент кода:

void f(valarray<double>& d)
{
    slice_array<double>& v_even = d[slice(0,d.size()/2,2)];
    slice_array<double>& v_odd = d[slice(1,d.size()/2,2)];

    v_odd *= v_even;
    v_even = 0;
}

Проблема заключается в том, что v_even и v_odd являются неконстантными ссылками на временные разделы, что недопустимо. И попытка скомпилировать это испускает ошибку:

error: non-const lvalue reference to type 'slice_array<double>' cannot bind to a temporary of type 'slice_array<double>'
    slice_array<double>& v_even = d[slice(0,d.size()/2,2)];
                         ^        ~~~~~~~~~~~~~~~~~~~~~~~~

Я проверил все доступные ошибки в сети, и нет ничего, что касалось этой фундаментальной проблемы. Я что-то упускаю? Изменился ли этот язык в связи с тем, что книга была напечатана (маловероятно, поскольку сама книга упоминает правило против неконстантных ссылок на временные)? Что здесь происходит?


Если я изменяю функцию, чтобы использовать значения вместо ссылок, например. slice_array<double> v_even = ..., то это фактически компилируется. Однако выясняется, что мои локальные заголовки С++ делают публичный конструктор копий, тогда как Stroustrup и различные онлайн-ссылки (cppreference.com, cplusplus.com) утверждают, что конструктор копирования является закрытым. Я предполагаю, что это решение не переносится. Это подкрепляется тем фактом, что Stroustrup явно перечисляет образец кода с неосновными переменными и говорит, что это приводит к ошибке.


Спецификация С++ 98 (PDF) объявляет slice_array<T> как имеющий закрытый конструктор копирования. К 2005 году (согласно эта спецификация), и предположительно как часть С++ 03, это изменилось на публичный конструктор копий.

4b9b3361

Ответ 1

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

"Лучшее" решение, я считаю, состоит в следующем:

void f(valarray<double>& d)
{
    const slice_array<double>& v_even = d[slice(0,d.size()/2,2)];
    const slice_array<double>& v_odd = d[slice(1,d.size()/2,2)];

    v_odd *= v_even;
    v_even = 0;
}

Все операторы на slice_array<T> определяются как const, поскольку они не изменяют сам срез, а содержимое. Они неверно определены в книге как не const.

Ответ 2

Это, кажется, опубликовано в errata (хотя ссылка сейчас мертва).

Однако Google отлично, он показывает привязку к поиску, подобному этому "slice_array & v_even"

Stroustrup: Исправление для 3-й печати программы на С++ Язык
www.research.att.com/~bs/3rd_printing4.html
[Cached] [Share] Общий доступ в Google+.
Посмотреть сообщение.
Вы публиковали это публично. Отмена

void f(valarray<double>& d)
{
    slice_array<double>& v_even = d[slice(0,d.size()/2, 2)];
    slice_array<double>& v_odd  = d[slice(1,d.size()/2,2)];

    v_odd *= 2; // double ...

EDIT: - О, спасибо за редактирование Кевин, это не ошибка. Я вижу, что в N3092 ясно сказано (§ 26.6.1, стр. 944)

4. Реализации, вводящие такие типы замены, должны обеспечивать дополнительные функции и операторы:
- для каждого функция, принимающая const valarray &, идентичные функции, принимающие добавляются типы замещения;
- для каждой функции, принимающей два const valarray & аргументы, идентичные функции, принимающие каждый комбинация const valarray & и типы замены должны быть добавлен.

5. В частности, реализация должна допускать, чтобы valarray построенных из таких типов замены и позволяющих выполнять задания и вычисляемые присвоения таких типов valarray, slice_array,gslice_array, mask_array и косвенные объекты.

Далее мой компилятор не дает никаких проблем (в настоящее время VS 2010) с кодом, компилируется отлично.