2013-07-15 3 views
-2

Можно ли бросить последние 3 элементы std::array<double, 4> в std::array<double, 3>?Cast некоторые элементы станд :: массива короткий станд :: массив

Например:

void f(std::array<double,3> &); 
... 
int main() { 
    std::array<double,4> a; 
    ... 
    f(/* pass a[1], a[2] and a[3] */); 
} 

РЕДАКТИРОВАТЬ:

Контекст: Есть несколько спиновых решетчатых (точечных) свойств, которые вычисляются с помощью различных функций (различные F() - с). Эти функции должны заполнять различные части массива. (Массив не может быть структурой, потому что числовые элементы зависят от аргументов времени компиляции.) Те f() - s называются миллионы раз.

+12

Сделайте свою функцию двумя итераторами. – chris

+0

Да, +1 к этому. Диапазоны в C++ должны быть переданы с использованием итераторов. –

+0

@chris Время критического приложения. Мне нужно это во время компиляции. – Predrag

ответ

7

Там нет простого способа сделать это, сохраняя вашу функцию тем же, чем это:

std::array<double, 3> temp{a[1], a[2], a[3]}; 
f(temp); 

Вместо этого сделать ваши функции принимают два итератора, и она работает гораздо больше, чем std::array с 3-х элементов :

template<typename Iter> 
void f(Iter first, Iter last); 

f(std::next(std::begin(a)), std::end(a)); 
-2

Вы можете попробовать союз:

int main() { 
    union U { 
     std::array<double,4> a; 
     struct { 
      double dummy; 
      std::array<double,3> a; 
     } s; 
    } u; 
    std::array<double,4> &a = u.a; 
    std::array<double,3> &a1 = u.s.a; 
    ... 
    f(a1); 
} 

Он должен Wo rk, но я не совсем уверен в переносимости ...

+2

Я считаю, что это технически неопределенное поведение, но профсоюзные трюки на самом деле довольно распространены. – chris

+0

@chris: возможно, но IIRC 'std :: array' типа POD также является POD-типом, и, кроме того, макет совместим с эквивалентным простым старым массивом. Таким образом, вопрос будет состоять в том, что мой союз будет UB даже с обычными массивами, но я действительно никогда не узнал все правила союзов ... – rodrigo

+3

Я уверен, что он, скорее всего, сработает, но чтобы получить любую ценность, t последний набор официально UB. – chris

0

Вы можете попробовать эту альтернативу. Таким образом, ваша функция будет принимать любой массив, который вы хотите. Он должен быть определен в файле .h

template<typename Type> void f(Type &arr) 
{ 
for (auto it=arr.rbegin(),int i=0;it!=arr.rend();++it,i++) 
    { 
    if (i < N)//<-- Your last N elements of arr 
    std::cout << (*it) << std::endl; 
    } 
} 

Путь назвать будет следующим:

int main() 
{ 
std::array<double,3> test1; 
f(test1); 
} 

Примечание: Вы не указали, как вы получите последние N элементы. Но есть несколько способов.

+0

Я не хочу, чтобы _all_ элементы 'test1' передавались в f(). – Predrag

+0

Затем уменьшите его, прежде чем передавать его функции ...? – KiaMorot

+0

Пример? (Без копирования/перемещения.) – Predrag

0

С std::array является стандартным типом (при условии, конечно, что внутренний тип, конечно), и, кроме того, макет совместим с простым старым массивом, следующее литье должно получить то, что вам нужно.

f(reinterpret_cast<std::array<double,3>&>(a)); 

Теперь этот бросок некрасиво, как ад, так что некоторые облегченная запись в порядке:

template<size_t N2, typename T, size_t N1> 
std::array<T, N2> resize_array(std::array<T,N1> &a, int offset) 
{ 
    return reinterpret_cast<std::array<T,N2>&>(a[offset]); 
} 
... 
f(resize_array<3>(a, 1)); 

Если смещение составитель константа вы могли бы сделать это также параметр шаблона, и вы могли бы даже заставить компилятор проверить диапазон! Но это остается как упражнение для читателя.

+2

Конечно, это все еще UB, потому что он нарушает строгий псевдоним. –

+0

Является ли это действительно совместимым с массивом? Вот определение совместимости с макетами: «Если два типа T1 и T2 одного типа, то T1 и T2 являются совместимыми с макетами типами. [Примечание: перечисления, совместимые с макетами , перечислены в 7.2. Структуры стандартного макета, совместимые с макетами и стандартные макеты союзы описаны в 9.2. -end note] ". Ни простые старые массивы не являются структурами, перечислениями или объединениями. И, очевидно, массивы не одного типа. (FWIW, я думаю, что глупо, что они не совместимы с макетами: S) –

+0

@ R.MartinhoFernandes: Хорошо, формального определения макетов, совместимых с макетами, нет, но это, вероятно, потому, что массивы должны иметь непрерывную память в любом случае, поэтому любой кусок массива должен быть совместим с другими (совместимыми с макетами типами). Теперь, что 'std :: array ' является макетом, совместимым с 'T [n]', не указывается явно нигде, о котором я знаю, но я считаю, что это намерение стандарта (несколько похожее на непрерывное требование 'std :: vector' в C++ 98). – rodrigo

1

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

template<size_t N> void f(double*); 
... 
int main() { 
    std::array<double,4> a; 
    ... 
    f<3>(a.data()); 
} 

ИМХО это не лучше, чем просто проходя два итератора, хотя. Если f может быть встроен, компилятор сможет оптимизировать перемещение с a.begin() до a.begin()+3, а также если вы пройдете его array<double, 3> (если вы обратили внимание, вы заметите, что постоянная 3 является постоянной во всех случаях.)

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