2015-03-24 13 views
5

के बीच रूपांतरण boost::tuple और std::tuple को देखते हुए, आप उनके बीच कैसे परिवर्तित होते हैं?std :: tuple और boost :: tuple

दूसरे शब्दों में, आप निम्नलिखित दो कार्यों को कैसे कार्यान्वित करेंगे?

template <typename... T> boost::tuple<T...> asBoostTuple( std::tuple<T...> stdTuple); 
template <typename... T> std::tuple<T...> asStdTuple (boost::tuple<T...> boostTuple); 

एक सीधा चीज लगता है, लेकिन मुझे कोई अच्छा समाधान नहीं मिला।


मैंने क्या प्रयास किया?

मैंने इसे टेम्पलेट प्रोग्रामिंग के साथ हल करने का अंत किया। ऐसा लगता है कि यह मेरे कंक्रीट सेटअप में काम करता है, लेकिन यह सही नहीं लगता है (बहुत वर्बोज़), और मुझे यह भी यकीन नहीं है कि यह वास्तव में सभी परिस्थितियों में काम करता है (मैं बाद में उस बिंदु पर आऊंगा)।

template<int offset, typename... T> 
struct CopyStdTupleHelper 
{ 
    static void copy(boost::tuple<T...> source, std::tuple<T...>& target) { 
     std::get<offset>(target) = std::move(boost::get<offset>(source)); 
     CopyStdTupleHelper<offset - 1, T...>::copy(source, target); 
    } 

    static void copy(std::tuple<T...> source, boost::tuple<T...>& target) { 
     boost::get<offset>(target) = std::move(std::get<offset>(source)); 
     CopyStdTupleHelper<offset - 1, T...>::copy(source, target); 
    } 
}; 

template<typename... T> 
struct CopyStdTupleHelper<-1, T...> 
{ 
    static void copy(boost::tuple<T...> source, std::tuple<T...>& target) 
     { /* nothing to do (end of recursion) */ } 

    static void copy(std::tuple<T...> source, boost::tuple<T...>& target) 
     { /* nothing to do (end of recursion) */ } 
}; 


std::tuple<T...> asStdTuple(boost::tuple<T...> boostTuple) { 
    std::tuple<T...> result; 
    CopyStdTupleHelper<sizeof...(T) - 1, T...>::copy(std::move(boostTuple), result); 
    return result; 
} 

boost::tuple<T...> asBoostTuple(std::tuple<T...> stdTuple) { 
    boost::tuple<T...> result; 
    CopyStdTupleHelper<sizeof...(T) - 1, T...>::copy(std::move(stdTuple), result); 
    return result; 
} 

मुझे आश्चर्य है कि अगर वहाँ एक और अधिक सुरुचिपूर्ण तरीका है:

वैसे भी, यहाँ दिलचस्प हिस्सा है। यह boost::tuple से std::tuple का उपयोग कर मौजूदा एपीआई को लपेटने के लिए एक बहुत ही आम ऑपरेशन की तरह लगता है।


मैं एक न्यूनतम परीक्षण उदाहरण है, जहां केवल asBoostTuple और asStdTuple के कार्यान्वयन याद आ रही है के साथ आप प्रदान करने की कोशिश की। हालांकि, boost::tuples::null_type के साथ कुछ जादू के लिए, जिसे मैं पूरी तरह समझ नहीं पा रहा हूं, यह संकलन करने में विफल रहता है। यही कारण है कि मुझे यकीन नहीं है कि मेरा मौजूदा समाधान आम तौर पर लागू किया जा सकता है।

#include <tuple> 
#include <boost/tuple/tuple.hpp> 

template <typename... T> 
boost::tuple<T...> asBoostTuple(std::tuple<T...> stdTuple) { 
    boost::tuple<T...> result; 
    // TODO: ... 
    return result; 
} 

template <typename... T> 
std::tuple<T...> asStdTuple(boost::tuple<T...> boostTuple) { 
    std::tuple<T...> result; 
    // TODO: ... 
    return result; 
} 

int main() { 
    boost::tuple<std::string, int, char> x = asBoostTuple(std::make_tuple("A", 1, 'x')); 

    // ERROR: 
    std::tuple<std::string, int, char> y = asStdTuple<std::string, int, char>(x); 

    return x == y; 
} 

त्रुटि संदेश है:

example.cpp:20:38: error: no viable conversion from 'tuple<[3 * 
     ...], boost::tuples::null_type, boost::tuples::null_type, 
     boost::tuples::null_type, boost::tuples::null_type, 
     boost::tuples::null_type, boost::tuples::null_type, 
     boost::tuples::null_type>' to 'tuple<[3 * ...], (no 
     argument), (no argument), (no argument), (no argument), 
     (no argument), (no argument), (no argument)>' 
    ...int, char> y = asStdTuple<std::string, int, char>(x); 

मैं समझता हूँ कि बूस्ट के कार्यान्वयन variadic टेम्पलेट्स, जो null_type व्याख्या करनी चाहिए पर आधारित नहीं है, लेकिन फिर भी मैं

यहाँ टुकड़ा है मुझे यकीन नहीं है कि संकलन त्रुटि से कैसे बचें।

उत्तर

10

इस तरह के मैनिप्लेशंस करते समय सामान्य चाल एक पूर्णांक अनुक्रम का निर्माण करना है और फिर नए ट्यूपल को प्रारंभ करने के लिए पैक विस्तार का उपयोग करना है।

इस मामले में अतिरिक्त मोड़ null_type है। इसके लिए ट्यूपल प्रकार को अपारदर्शी के रूप में इलाज करना शायद सबसे आसान है, और boost::tuples::length और boost::tuples::element का उपयोग करके इसे कुशलतापूर्वक उपयोग करें, जो पहले से ही null_type को ठीक से संभालता है। इस तरह आप बूस्ट टुपल्स के कार्यान्वयन विवरण पर भरोसा नहीं करते हैं।

तो:

template <typename StdTuple, std::size_t... Is> 
auto asBoostTuple(StdTuple&& stdTuple, std::index_sequence<Is...>) { 
    return boost::tuple<std::tuple_element_t<Is, std::decay_t<StdTuple>>...> 
         (std::get<Is>(std::forward<StdTuple>(stdTuple))...); 
} 

template <typename BoostTuple, std::size_t... Is> 
auto asStdTuple(BoostTuple&& boostTuple, std::index_sequence<Is...>) { 
    return std::tuple<typename boost::tuples::element<Is, std::decay_t<BoostTuple>>::type...> 
        (boost::get<Is>(std::forward<BoostTuple>(boostTuple))...); 
} 

template <typename StdTuple> 
auto asBoostTuple(StdTuple&& stdTuple) { 
    return asBoostTuple(std::forward<StdTuple>(stdTuple), 
      std::make_index_sequence<std::tuple_size<std::decay_t<StdTuple>>::value>()); 
} 

template <typename BoostTuple> 
auto asStdTuple(BoostTuple&& boostTuple) { 
    return asStdTuple(std::forward<BoostTuple>(boostTuple), 
      std::make_index_sequence<boost::tuples::length<std::decay_t<BoostTuple>>::value>()); 
} 

Demo

ध्यान दें कि कोड के बुनियादी ढांचे को दो स्थितियों के लिए वास्तव में समान होता है: हम टपल (boost::tuples::length या std::tuple_size के माध्यम से) के आकार को प्राप्त करने, एक पूर्णांक अनुक्रम std::make_index_sequence का उपयोग कर निर्माण, और फिर प्राप्त करने के लिए पूर्णांक अनुक्रम का उपयोग boost::tuples::element और std::tuple_element के साथ प्रकार, और boost::get/std::get वाले मान।

संबंधित मुद्दे