2017-03-17 18 views
6

I chcą efektywnie pomnażać argumenty z pakietem parametrów z elementami std :: tablicy:C++ 17 skutecznie mnożyć argumenty parametr pack z elementów tablicy std ::

int index(auto... Is, std::array<int,sizeof...(Is)> strides) 
{ 
    // pseudo-code 
    // int idx = 0; 
    // for(int i = 0; i < sizeof...(Is); ++i) 
    // idx += Is[i] * strides[i]; 
    // return idx; 
} 

nie mogę dość otoczyłem mój mózg wokół tego. Zacząłem od sekwencji indeksowania, ale mogłem wymyślić, jak włączyć sumowanie.

Używam C++ 17, więc wyrazy są fair fair, jeśli uprościłoby kod.

Dzięki za wszelkie wskazówki.

EDYCJA: Skorygowano pseudokod. Jedyną pseudo częścią jest wyrażenie Is[i], które odnosi się do argumentu i'th parametru pack.

odpowiedź TC poniżej była idealna, a tu jest mój ostateczny kod, który jest funkcją członkiem:

unsigned int index(auto... indexes) 
{ 
    unsigned int idx = 0, i = 0; 
    (..., (idx += indexes * m_strides[i++])); 
    return idx; 
} 

W chwili pisania tego, kod kompiluje używając gcc 6.3.0 z -fconcepts flagą, która wprowadza koncepcję TS.

Stosowanie auto... indexes jest skrótem dla template<typename Args> f(Args... indexes). Próbowałem użyć niepodpisanego pojęcia int dla argumentów, ale nie mogłem zmusić tego do działania.

The (...) rozkładana jest kluczowym elementem i rozszerza się na coś podobnego (jeśli faktycznie mogła [] do plecaka parametru):

idx += indexes[0] * m_strides[i++], idx += indexes[1] * m_strides[i++], etc. 

To był wgląd mi brakuje.

+0

Jestem ciekaw co kompilator używasz. – ThomasMcLeod

+0

@ThomasMcLeod gcc 6.3.0 - ma składanie wyrażeń i kilka innych funkcji C++ 17. – RandomBits

+1

@ThomasMcLeod GCC 7 ma ukończone C++ 17 (nie jest to jednak libstdC++) –

Odpowiedz

3

Nie mogę uzyskać auto... do pracy, więc zmieniono podpis index.

Będziesz potrzebować funkcji pomocniczej (tutaj: index_helper), aby użyć index_sequence, ponieważ polega ona na odliczeniu argumentów w szablonie w celu wypełnienia indeksów.

#include <array> 
#include <cstdio> 

template <typename... T, size_t... i> 
//      ^~~~~~~~~~~ 
//      use deduction to make {i...} = {0, 1, 2, ..., n} 
static int index_helper(const std::array<int, sizeof...(T)>& strides, 
         std::index_sequence<i...>, 
         T... Is) 
{ 
    return (0 + ... + (strides[i] * Is)); 
} 

template <typename... T> 
int index(const std::array<int, sizeof...(T)>& strides, T... Is) { 
    return index_helper(strides, std::make_index_sequence<sizeof...(T)>(), Is...); 
//        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
//        generates {0, 1, 2, ..., n} 
} 

int main() { 
    printf("%d\n", index({1, 100, 100000, 1000}, 2, 3, 5, 7)); 
    // 507302 
} 
+0

Głupio, aby nie "constexpr" dane typy. : -] – ildjarn

1

Jeśli można zaklepać pakiet argumentów w jeden typ, który jest tani skopiować/przenieść, można po prostu uczynić go do tablicy:

T arr[] = { static_cast<T>(Is)... }; // for some T, possibly common_type_t<decltype(Is)...> 

Następnie można po prostu włączyć swoje Pseudokod do prawdziwego kodu.

Jeśli nie jest to możliwe, składanym przecinek można stosować:

int idx = 0, i = 0; 
(..., (idx += Is * strides[i++])); 
return idx; 
+0

Nie zdawałem sobie sprawy, że możesz użyć i zmodyfikować zmienną indeksową w takiej pozycji. To jest przydatne. – RandomBits