2014-07-18 18 views
12

सी ++ 14 में, सामान्यीकृत लैम्ब्डा कब्जा हमें करते हैं:सामान्यीकृत लैम्ब्डा परम-पैक पर कब्जा?

template<class T> 
auto pack(T t) 
{ 
    return [t=std::move(t)](auto&& f){f(t);}; 
}; 

लेकिन यह परम-पैक के साथ खेलने नहीं करता है:

template<class... T> 
auto pack(T... t) 
{ 
    return [t=std::move(t)...](auto&& f){f(t...);}; 
}; 

कोई विशेष सिंटेक्स या करने के लिए आगे मानक प्रस्ताव है इसे संबोधित करें?

+1

'&' को कैप्चर करने और 'f (std :: move (t) ...) 'का उपयोग करने में आपको क्या समस्या है? – chris

+1

@ क्रिसिस जैसे ही 'पैक' रिटर्न के रूप में संदर्भ लटक जाएंगे, नहीं? – Brian

+0

@ ब्रायन, ओह हाँ, अच्छा बिंदु। मैंने नहीं देखा कि यह वापस किया जा रहा था। – chris

उत्तर

16

सी ++ 14 वर्ष की मेरी मसौदा कहते हैं ([expr.prim.lambda]/24):

एक सरल कब्जा एक अंडाकार के बाद एक पैकेट विस्तार (14.5.3) है। एक init-capture इसके बाद एक इलिप्सिस खराब हो गया है।

तो ऐसा लगता है कि एक भिन्न सामान्यीकृत कैप्चर करने का कोई तरीका नहीं है। एक संभावित समाधान, सिर्फ एक टपल में तर्क कब्जा करने के लिए और उसके बाद का उपयोग समाधानों में से एक यहाँ का सुझाव दिया है:

template<class T> 
struct mover 
{ 
    mover(T const& val) : val(val) {} 

    mover(T&& val) : val(std::move(val)) {} 

    mover(mover const& other) = default; 

    mover(mover&& other) = default; 

    mover(mover& other) : val(std::move(other.val)) {} 

    operator T const&() const 
    { 
     return val; 
    } 

    T val; 
}; 

template<class T> 
using wrap_t = typename std::conditional 
    < 
     std::is_move_constructible<T>::value 
    && !std::is_trivially_copy_constructible<T>::value 
     , mover<T> 
     , T 
    >::type; 

template<class... Ts> 
auto pack_impl(wrap_t<Ts>... ts) 
{ 
    return [=](auto&& f)->decltype(auto) 
    { 
     return f(static_cast<Ts const&>(ts)...); 
    }; 
} 

auto pack = [](auto&&... ts) 
{ 
    return pack_impl<std::decay_t<decltype(ts)>...>(static_cast<decltype(ts)>(ts)...); 
}; 

यह: "unpacking" a tuple to call a matching function pointer

auto pack(T... t) 
{ 
    return [args=make_tuple(std::move(t)...)](auto&& f){ 
       // find a way to call f with args 
      }; 
}; 
+1

"एलीप्सिस के बाद एक इनिट-कैप्चर बीमार है", इसलिए ड्राफ्ट लेखक इस संभावित उपयोग से अवगत हैं और इसका समर्थन नहीं करना चाहते हैं? हम्म ... – Jamboree

+0

@ जंबोरी मुझे ऐसा लगता है। हो सकता है कि कुछ तकनीकी मुद्दे हैं जो समर्थन करना मुश्किल बनाते हैं, या हो सकता है कि जो भी इन-कैप्चर के लिए प्रस्ताव प्रस्तुत करता है, उसे सरल रखना चाहता था। – Brian

+3

@ जंबोरी यहां एक चर्चा है: https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/ePRzn4K7VcM – Brian

3

एक अनुवर्ती के रूप में, मैं इस समाधान के लिए आया था प्रॉक्सी के रूप में mover का उपयोग करता है, जो लैम्ब्डा को इसे स्थानांतरित करने की अनुमति देता है (यह थोड़ा हैकी है)। और wrap_tmover लागू करने के लिए आवश्यक या लाभकारी होने का निर्णय लेता है।

अब हम यह परीक्षण कर सकते हैं:

struct A 
{ 
    A() = default; 

    A(A&&) 
    { 
     std::cout << "move\n"; 
    } 

    A(A const&) 
    { 
     std::cout << "copy\n"; 
    } 
}; 

A a; 
std::cout <<"p1------------\n"; 
auto p1 = pack(std::move(a)); 
std::cout <<"p2------------\n"; 
auto p2 = std::move(p1); 
std::cout <<"p3------------\n"; 
auto p3 = p2; 

प्रिंट होगा:

p1------------ 
move 
move 
p2------------ 
move 
p3------------ 
copy 
3

यह ऊपर ब्रायन जवाब देने के लिए मेरी टिप्पणी पर फैलता है। C++ पुस्तकालय बुनियादी बातों टीएस के साथ 14 आप कर सकते हैं:

template<class... T> 
auto pack(T... t) 
{ 
    return [ts = std::make_tuple(std::move(t)...)](auto&& f){ 
     std::experimental::apply(f, ts); 
    }; 
}; 

, मान लें कि आप चाहते हैं सामान्य रूप से इस कदम से एक पैरामीटर पैक को पकड़ने और एक लैम्ब्डा के भीतर इसका इस्तेमाल आप एक लैम्ब्डा के भीतर एक लैम्ब्डा में कोड लिख सकते हैं और फिर इस पर तर्क लागू करें:

[ts = std::make_tuple(std::move(t)...)](/* args */){ 
    auto lambda = [&](auto&&... args) { 
     // - args is the original parameter pack that one wanted to 
     // capture by move 
     // - the other arguments can be used by reference 
    }; 
    return std::experimental::apply(lambda, ts); 
}; 
संबंधित मुद्दे