Допустимо ли совмещение массива T с массивом std :: complex <T>? - PullRequest
0 голосов
/ 18 октября 2018

Мне известно о строгом правиле наложения типов.Однако cppreference отмечает, что

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

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

std::size_t numDoubles = 100;
double* a = (double*) std::malloc(numDoubles * sizeof(double));
std::complex<double>* b = reinterpret_cast<std::complex<double>*>(a);
DoSomethingWith(b[1]);

Изменится ли ответ, если new [] используется для генерации двойного массива?

XY Проблема Объяснение:Я пытаюсь абстрагироваться от распределителя, предоставленного сторонней библиотекой, которая может отсутствовать;этот распределитель возвращает пустоту *;Я пытаюсь избежать попадания в заголовок информации о том, что делает библиотека.Итак, у меня есть такая структура:

// foo.h
namespace impl {
    void* Allocate(std::size_t numBytes);
}

template<typename T>
T* Allocate(std::size_t num) {
    static_assert(std::is_pod_v<T>);
    return static_cast<T*>(Allocate(num * sizeof(T)));
}


// foo.cpp
#if LIBRARY_PRESENT

void* impl::Allocate(std::size_t numBytes) { return LibraryAllocate(numBytes); }

#else

void* impl::Allocate(std::size_t numBytes) { return std::malloc(numBytes); }

#endif

К сожалению, std :: complex не является POD, потому что он имеет нетривиальный конструктор по умолчанию.Я надеюсь, что смогу игнорировать эту проблему.

Ответы [ 2 ]

0 голосов
/ 18 октября 2018

Таким образом, стандартный раздел [complex.numbers] p4 говорит следующее:

Если z является lvalue типа cv complex, тогда:

  • выражение reinterpret_cast (z) должно быть правильно сформировано,
  • reinterpret_cast (z) [0] должно обозначать действительную часть z, а
  • reinterpret_cast (z) [1] должнообозначить мнимую часть z.

Более того, если a является выражением типа cv complex * и выражение a [i] определено для целочисленного выражения i, то:

  • reinterpret_cast (a) [2 * i] обозначает действительную часть [i], а
  • reinterpret_cast (a) [2 * i + 1] обозначает мнимую частьa [i].

Это не исключение из правила строгого алиасинга с другой стороны, так что похоже, что оно не подходит для псевдонима std::complex<double> через double .

Использование нового не меняет анализ.

0 голосов
/ 18 октября 2018

Допускает ли это требование допустимость кода, подобного следующему

Этот код не является строго законным, даже если вы использовали a напрямую вместо приведения к complex,Объектная модель C ++ не позволяет вам просто захватить некоторую память, привести ее к типу и сделать вид, что объекты существуют в этой памяти.Это верно независимо от типа (вне байтовых типов).

Этот код никогда не создает массив double, поэтому вы не можете получить доступ к памяти, как если бы там был массив double.Вы также не можете получить доступ к complex<double>, как если бы он был там.

Изменится ли ответ, если new[] используется для создания массива двойных значений?

Только в том смысле, что будет допустимый массив double.Там по-прежнему нет complex<double>.

Правило, которое обеспечивает std::complex<T>, заключается в том, что вы можете получить доступ к его элементам, как если бы это был массив из двух T s . не означает, что вы можете получить доступ к любому массиву из двух T с, как если бы это был std::complex<T>.

...