2015-05-29 10 views
5

के लिए पॉलिमॉर्फिक सेटटर मैं टेम्पलेट प्रकारों के साथ boost :: संस्करण का उपयोग करने की कोशिश कर रहा हूं। उदाहरण के लिए, मेरे पास एक टेम्पलेट प्रकार Tag<T> है और boost :: संस्करण AnyTag में Tag<double>, Tag<int> और Tag<std::string> जैसे प्रकार शामिल हैं। प्रत्येक Tag<T> प्रकार टी के सदस्यों अब है, मैं एक कंटेनर में उन वेरिएंट डाल करने के लिए और केवल रनटाइम के दौरान मान निर्दिष्ट जैसे चाहते हैं,Boost :: variant

for(AnyTag & tag: AllTags) { 
    setValue(tag, getValueFromXml()); 
} 

समारोह setValue(AnyTag &tag, T &val) में AnyTag टैग के क्रम प्रकार का उपयोग करना चाहिए सही मूल्य के साथ टैग सही ढंग से असाइन करने के लिए आदेश। समस्या को हल करने का मेरा प्रयास नीचे पाया जा सकता है और यह किसी अन्य संस्करण का उपयोग करता है जिसमें केवल संभावित टी प्रकार शामिल होते हैं जिनका उपयोग AnyTag (TagValueType) में किया जा सकता है।

template<typename T, typename = void> 
class Tag {}; 

template <typename T> 
class Tag<T, EnableIf<std::is_arithmetic<T>>> { 
public: 
    T value = 0; 
    std::string address = ""; 
    T maxValue = std::numeric_limits<T>::max(); 
    typedef T value_type; 
}; 

template <typename T> 
class Tag<T, DisableIf<std::is_arithmetic<T>>> { 
public: 
    T value; 
    std::string address = ""; 
    typedef T value_type; 
}; 

typedef boost::variant<Tag<std::string>, 
         Tag<double>, 
         Tag<int>, 
         > AnyTag; 

typedef boost::variant<std::string, double, int> TagValueType; 

class tag_set_value_visitor: public boost::static_visitor<void> 
{ 
    const TagValueType & value; 
public: 
    tag_set_value_visitor(const TagValueType & val): value(val){} 
    template <typename T> 
    void operator()(T & tag) const 
    { 
     tag.value = boost::get<typename T::value_type>(value); 
    } 
}; 

inline void setValue(AnyTag & tag, const TagValueType & val) { 
    assert(tag.which() == val.which()); 
    boost::apply_visitor(tag_set_value_visitor(val), tag); 
} 

दुर्भाग्य से, यह तरीका नहीं है मैं क्योंकि संकलन के दौरान उदाहरण के लिए क्या चाहते हैं वहाँ समस्या नहीं है अगर मैं निम्न कार्य करें:

AnyTag a = Tag<int>(); 
setValue(a, double(1.3)); 

लेकिन रनटाइम के दौरान, बढ़ावा पुस्तकालय प्रकार मेल नहीं खाता का पता लगाता है और कार्यक्रम दुर्घटनाग्रस्त हो जाता है।

तो, मेरा समाधान एक प्रकार का मिरर है जो सिर्फ समस्या को स्थगित करता है।

मैं जो सेट करना चाहता हूं वह एक सेटव्यू (AnyTag & टैग, टी & वैल) है जहां टी AnyTag का रनटाइम प्रकार है।

मुझे लगता है कि संस्करण का विज़िटर ऐसा करने का प्रयास करता है, लेकिन इस मामले में एक समस्या है क्योंकि जब हम विज़िटर का निर्माण करते हैं तो हमें उस प्रकार को जानना चाहिए जिसे हम उपयोग करने जा रहे हैं।

इस समस्या के बारे में कोई विचार या कोई विचार?

पीएस .: लंबी पोस्ट के लिए खेद है लेकिन मुझे कम शब्दों के साथ मेरी विचार प्रक्रिया को समझाने का कोई तरीका नहीं मिला।

+0

'सेटवैल्यू (ए, डबल (1.3))' में, आप संकलक को समस्या का पता लगाने की अपेक्षा कैसे करते हैं जब समस्या _run-time_ प्रकार 'a' है? – Nemo

+0

नीमो, मैं नहीं करता। मैंने कहीं लिखा है कि मैं जो कर रहा हूं वह सिर्फ समस्या को स्थगित कर रहा है।क्या मैं करना चाहते हैं ("आराम" वाक्य रचना में) है: उत्पन्न setValue (AnyTag :: टैग 1) संकलक और, पूर्णांक और वैल) setValue (AnyTag :: टैग और, डबल और वैल) 2) और उसके बाद रनटाइम के दौरान polymorphically Anytag के रन-टाइम प्रकार के आधार पर सही सेटवैल्यू (...) का चयन करें। – CuriousNik

+0

मैं समझता हूं कि प्रेषण सी ++ में इस तरह से नहीं हो सकता है, इसलिए मैं सोच रहा था कि शायद कोई चाल (विज़िटर पैटर्न के साथ) जानता है जो इस समस्या को हल कर सकता है। – CuriousNik

उत्तर

6

एक बाइनरी विज़िटर का उपयोग करें।

संबंधित प्रकारों को छोड़कर कुछ भी करने के लिए operator() लागू करें।

हैंडल बेमेल स्वाद के लिए (मैं एक बूलियन का संकेत सफलता वापसी):

Live On Coliru

#include <boost/any.hpp> 
#include <boost/variant.hpp> 
#include <boost/mpl/vector.hpp> 
#include <string> 

using namespace boost; 

template <typename T> 
struct Tag { 
    T value; 
}; 

using Types = mpl::vector<std::string, double, int>; 
using Tags = mpl::transform<Types, Tag<mpl::_1> >::type; 

using Variant = make_variant_over<Types>::type; 
using AnyTag = make_variant_over<Tags>::type; 

namespace mydetail { 
    struct assign_to : boost::static_visitor<bool> { 
     template <typename V> bool operator()(Tag<V>& tagged, V const& value) const { 
      tagged.value = value; 
      return true; 
     } 

     template <typename T, typename V> bool operator()(T&&, V&&) const { 
      return false; 
     } 
    }; 
} 

bool setValue(AnyTag &tag, Variant const& val) { 
    return boost::apply_visitor(mydetail::assign_to(), tag, val); 
} 

int main() { 
    AnyTag t; 

    t = Tag<std::string>(); 

    // corresponding type assigns and returns true: 
    assert(setValue(t, "yes works")); 

    // mismatch: no effect and returns false: 
    assert(!setValue(t, 42)); 
    assert(!setValue(t, 3.1415926)); 
} 

¹ अगर मैं अपने लक्ष्य को सही ढंग से समझा। मैंने पर ध्यान केंद्रित किया है "मैं जो सेट करना चाहता हूं वह एक सेटवैल्यू (AnyTag & टैग, टी & वैल) है जहां टी AnyTag का रनटाइम प्रकार है।" अनुरोध के भाग।

+0

बहुत बहुत धन्यवाद, sehe। जैसा मुझे चाहिए था यह बिल्कुल वैसा ही है। दुर्भाग्य से, मैं आपके उत्तर को अप-वोट नहीं कर सकता क्योंकि मेरे पास पर्याप्त प्रतिष्ठा अंक नहीं हैं। मैं उस चाल को देखता हूं जो आपने किया था और मैंने इस तरह से बिल्कुल नहीं सोचा था। इसके अलावा, आपने मेरा ध्यान boost :: mpl में लाया, ताकि मैं इन प्रकार की घोषणाओं को दोहराना न पड़े। फिर से धन्यवाद! – CuriousNik

+0

हां! मुझे खुशी है कि आपने टाइपिस्टिस्ट ट्रांसफॉर्म के साथ छोटे विवरण को देखा :) चीयर्स – sehe

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