Un modo sarebbe quello di scrivere un funtore in senso Haskell. Beh, un variardico, che non è molto Haskell.
Scrivere una funzione della firma (Ts...)->(((Ts...)->X) -> X)
. Cioè una funzione che prende un pacchetto e restituisce una funzione. La funzione restituita può assumere una funzione tenendo quel pacchetto e valutarlo.
template<class...Ts>
auto make_functor(Ts&&...ts); // TODO
Una volta ottenuto ciò, possiamo risolvere facilmente il problema.
template<class ...A>
auto test(A&& ...a) {
return [unpack_a=make_functor(std::forward<A>(a)...)]() mutable
{
return unpack_a([&](auto&&...a){
// here you have access to a...
return sizeof...(a);
});
};
}
test
prende un pacco, e restituisce una funzione che restituisce la dimensione di tale pacchetto (beh, fa qualsiasi cosa con il pack).
make_functor
non è semplice: in pratica, scriviamo un lambda manuale, memorizzando gli arg in una tupla e decomprimendo il trucco dell'indice in un operatore().
In effetti, facciamo il pacchetto di archiviazione e disimballaggio una volta in una classe pseudo-lambda manuale, quindi riusciamo a riutilizzarlo in seguito.
A pensarci bene, potrebbe essere meglio scrivere una domanda ritardata che richiede una tupla, la memorizza, quindi usa std::apply
in seguito.
template<class...Ts>
auto delayed_apply(std::tuple<Ts...> tup){
return [tup=std::move(tup)](auto&&f)->decltype(auto) mutable{
return std::experimental::apply(decltype(f)(f), std::move(tup));
};
}
che consente di non perdere il valore/valore dei parametri!
template<class ...A>
auto test(A&& ...a) {
return [unpack_a=delayed_apply(std::forward_as_tuple(std::forward<A>(a)...))]() mutable
{
return unpack_a([&](auto&&...a){
// here you have access to a...
return sizeof...(a);
});
};
}
questo richiede std::experimental::apply
.
Se si vuole negozio rvalues e lasciare lvalue come riferimenti:
unpack_a=delayed_apply(std::tuple<A...>(std::forward<A>(a)...))
Se si desidera memorizzare entrambi L e R valori:
unpack_a=delayed_apply(std::make_tuple(std::forward<A>(a)...))
come si può vedere, questo approccio dà molto controllo
Se è necessario un std::experimental::apply
, ci sono implementazioni di riferimento: meglio di quelle che scrivo su uno smartphone.
Si noti che make_functor
può essere scritto in termini di delayed_apply
, ma il contrario è ... non è vero.
In caso di confusione, unpack_a
prende una lambda e decomprime la tupla utilizzata per creare unpack_a
.Fondamentalmente noi immagazziniamo un oggetto che è l'intero pacchetto, quindi lo scompattiamo quando ne abbiamo bisogno all'interno del corpo del lambda.
Un tempo più lungo delayed_apply
che gestisce i sovraccarichi const e non-const e forse anche rvalue può essere richiesto se si desidera che la decompressione funzioni "più volte" e "solo una volta" altre volte. Dovrà restituire una classe, non una lambda. Fastidioso. Ho fatto funzionare il codice di esempio, penso, non ancora compilando.
Fortunatamente questo tipo di cose è scrivere una volta, usare molte.
Che ne dici di catturarlo per riferimento e quindi utilizzare in avanti all'interno del corpo lambda? Catturare per valore non lo farà per te. – Arunmu
Inoltre, se si potesse scrivere uno pseudo codice su cosa esattamente si vuole fare, sarebbe utile. – Arunmu
Come pensate di usare il vostro lambda? Inoltre, troppo male '[a = (std :: forward (a) ...)]() {};' non viene compilato. Il compilatore può ottimizzare l'acquisizione se non si usano gli argomenti da nessun'altra parte. – coyotte508