2015-05-09 24 views
6

Desidero preparare l'elenco di coppie di valori dalla struttura utilizzando modelli variadici.Espansione di modelli variadici diversi

#include <vector> 

struct foo 
{ 
    foo(int a, int b) 
     : a(a), b(b) {} 
    int a; 
    int b; 
}; 

struct Msg 
{ 
    std::vector<int> valueArray;  
}; 

template<typename... Args> 
Msg func(Args... args) 
{ 
    Msg msg; 
    msg.valueArray = { sizeof...(args), (args.a)..., (args.b)... }; 
    return msg; 
} 

int main() { 
    Msg msg = func(foo{1,2}, foo{3,4}, foo{5,6}); 
} 

Messaggio che func restituirà avrà valueArray = [3, 1, 3, 5, 2, 4, 6].

C'è un modo semplice per espandere i parametri di misura variadici in un modo, dove valueArray sarà simile a valueArray = [3, 1, 2, 3, 4, 5, 6]?

+0

Non è possibile assegnare ad array. – chris

+0

Sono stato modificato in vettore, ma questo non ha rivelato questa domanda;) – Xter

+0

Considerando che la tua domanda non utilizza i valori in fase di compilazione, una chiamata a 'std :: sort' dopo aver assegnato i valori codificati non dovrebbe essere? – chris

risposta

4

Il seguente non è così generico come mi piacerebbe, ma forse è sufficiente per voi:

template<typename Arr, std::size_t... Is> 
Msg func2(const Arr& arr, std::index_sequence<Is...>) 
{ 
    Msg msg; 
    msg.valueArray = { 
     sizeof...(Is)/2, 
     ((Is % 2 == 0) ? std::get<Is/2>(arr).a 
          : std::get<Is/2>(arr).b)... }; 
    return msg; 
} 

template<typename... Args> 
Msg func(Args... args) 
{ 
    return func2(std::forward_as_tuple(args...), 
        std::make_index_sequence< 2*sizeof...(Args) >()); 
} 

Live example

+1

Impossibile compilare con il pacchetto vuoto. Perché non usare 'forward_as_tuple' invece di una matrice di puntatore? – Jarod42

+0

@ Jarod42 Buona idea, ha aggiornato la risposta. –

3

Uso C++ 14 caratteristiche, una soluzione generale può essere ottenuto:

struct Msg { 
    std::vector<int> values; 
}; 

template <std::size_t... indices, typename Tuple, typename OutputIt> 
void copy(std::index_sequence<indices...>, Tuple&& t, OutputIt out) { 
    (void)std::initializer_list<int> { 
     (*out++ = std::get<indices>(std::forward<Tuple>(t)), 0)... 
    }; 
} 

template <typename Tuple, typename OutputIt> 
void copy(Tuple&& t, OutputIt out) { 
    copy(std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>{}>{}, 
     std::forward<Tuple>(t), out); 
} 

template <typename... Args> 
Msg func(Args... args) { 
    auto cat = std::tuple_cat(args...); 
    Msg m{{sizeof...(args)}}; 
    copy(cat, std::back_inserter(m.values)); 
    return m; 
} 

// For demonstration: 
template <typename... T> 
auto foo(T&&... t) {return std::make_tuple(std::forward<T>(t)...);} 

L'utilizzo è più flessibile rispetto a prima:

Msg msg = func(foo(1,2,3), foo(4), foo(5,6,7)); 

Demo.

È possibile definire foo come tupla (di dimensioni fisse), ad es. using foo = std::tuple<int, int>;, quindi l'esempio sopra riportato viene compilato senza la funzione ausiliaria (dopo aver regolato le parentesi, ovviamente).

+0

Sarei un po 'preoccupato per il runtime - le spese generali sono le cause, ma la domanda degli OP non è facile da risolvere in un modo elegante e senza costi generali - la mia risposta non è molto migliore, solo diversa. +1 –

Problemi correlati