2014-11-26 9 views
6

È possibile scegliere condizionalmente il metodo di cattura di una lambda sulla base delle informazioni sulla compilazione? Per esempio ...C++ 14 Lambda - Cattura condizionale per riferimento o valore

auto monad = [](auto && captive) { 
    return [(?)captive = std::forward<decltype(captive)>(captive)](auto && a) { 
     return 1; 
    }; 
}; 

voglio cattura da riferimento, se decltype(captive) è un std::reference_wrapper, e tutto il resto catturato per valore.

+1

Non è il punto di 'reference_wrapper' che è come un riferimento, tranne che può essere passato in giro per valore senza un problema? Perché allora * si * digita il tipo che vuoi catturare per riferimento? Cosa c'è di sbagliato nel catturare tutto per valore? – hvd

+0

@hvd Non voglio acquisire 'reference_wrapper' per riferimento, voglio catturare il riferimento che detiene per riferimento. Il reference wrapper è meglio essere un riferimento, ma dato che l'operatore di chiamata (noto anche come operatore ".") Non può essere sovraccaricato, alla fine della giornata fallisce in modo piuttosto miserabile. – pat

+0

Grazie per il chiarimento. Questo ha più senso. Quindi non vuoi catturare 'captive' per riferimento se è un' reference_wrapper', vuoi catturare 'captive.get()' per riferimento, giusto? – hvd

risposta

4

Il tipo di cattura lambda non può essere controllato da nomi dipendenti da modello.

Tuttavia, si potrebbe ottenere l'effetto desiderato, delegando la creazione lambda interna a una funzione di sovraccarico:

template<class T> 
auto make_monad(T&& arg) { 
    return [captive = std::forward<T>(arg)](auto&& a) { 
     std::cout << __PRETTY_FUNCTION__ << " " << a << '\n'; 
     return 1; 
    }; 
} 

template<class T> 
auto make_monad(std::reference_wrapper<T> arg) { 
    return [&captive = static_cast<T&>(arg)](auto&& a) { 
     std::cout << __PRETTY_FUNCTION__ << " " << a << '\n'; 
     return 1; 
    }; 
} 

int main() { 
    auto monad = [](auto&& captive) { 
     return make_monad(std::forward<decltype(captive)>(captive)); 
    }; 

    int n = 1; 
    monad(1)(1); 
    monad(n)(2); 
    monad(std::ref(n))(3); 
} 

Uscite:

make_monad(T&&)::<lambda(auto:1&&)> [with auto:1 = int; T = int] 1 
make_monad(T&&)::<lambda(auto:1&&)> [with auto:1 = int; T = int&] 2 
make_monad(std::reference_wrapper<_Tp>)::<lambda(auto:2&&)> [with auto:2 = int; T = int] 3 

io non voglio cattura reference_wrapper per riferimento, voglio catturare il riferimento che detiene per riferimento. Il reference wrapper è meglio essere un riferimento, ma dato che l'operatore di chiamata (noto anche come operatore ".") Non può essere sovraccaricato, alla fine della giornata fallisce in modo piuttosto miserabile.

In questo caso non è necessario modificare il tipo di acquisizione per std::reference_wrapper<T>. Invece, come si può catturare per valore come qualsiasi altro tipo di argomento e nel sito utilizzo scartare l'argomento prima:

template<class T> T& unwrap(T& t) { return t; } 
template<class T> T& unwrap(std::reference_wrapper<T> t) { return t; } 

auto monad = [](auto && captive) { 
    return [captive](auto && a) {   // <--- Capture by value. 
     auto& captive_ref = unwrap(captive); // <--- Unwrap before usage. 
     return 1; 
    }; 
}; 
+1

Grazie per la risposta!So che ci sono un sacco di modi per farlo in una vecchia scuola, speravo solo che il C++ 14 avrebbe permesso una certa brevità nella soluzione. – pat

+0

@Casey Molto probabilmente, la domanda originale, tuttavia, voleva catturare il wrapper come riferimento. –

+0

@Casey aggiornato. –

1

Non rispondere alla tua domanda, ma i suoi commenti, Come utilizzare operator .:

puoi aggiungere quei due overload:

template <typename T> 
T& get_reference_object(T&& t) { return t; } 

template <typename T> 
T& get_reference_object(std::reference_wrapper<T> t) { return t.get(); } 

e quindi si può utilizzare get_reference_object(arg).foo all'interno del vostro lambda:

auto monad = [](auto && captive) { 
    return [captive = captive](auto&& a) { return get_reference_object(captive).foo(a); }; 
}; 

Live example.

Problemi correlati