मैं एक std::unordered_map को लागू करने का प्रयास कर रहा हूं जो double, int या std::string के जोड़े लौटाता है। मानचित्र की कुंजियाँ std::strings हैं। नीचे मैंने अभी तक कोशिश की है:

#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <unordered_map>
#include <utility>
#include <vector>

// A base class for boundary class
class Boundbase {
    public:
    Boundbase(){};
    virtual ~Boundbase(){};
};

// A different map of boundaries for each different data type
template <class dType>
class Boundary : public Boundbase {
    std::pair<dType, dType> bpair;
    
    public:
    //Constructor
    Boundary(const std::string &lbound, 
        const std::string &ubound) {
        setbound(lbound, ubound);
    };

    //A method to set boundary pair
    void setbound(const std::string &lbound, 
        const std::string &ubound);
    
    // A method to get boundary pair
    std::pair<dType, dType> getbound() {return bpair;}
};

// Class to hold the different boundaries 
class Boundaries {
    std::unordered_map<std::string, Boundbase*> bounds;

    public:
    //Constructor
    Boundaries() {};

    // A method to set boundary map
    void setboundmap(std::unordered_map<std::string, 
            std::vector<std::string>> xtb);

    // A template to get boundaries.
    std::unordered_map<std::string, Boundbase*> getbounds()
        {return bounds;}
};

// A method to set covariate boundary
template <class dType> void
Boundary<dType>::setbound(const std::string &lbound, 
        const std::string &ubound) {
    dType val;
    std::istringstream isa(lbound);
    while(isa >> val) {
        bpair.first = val;
    }
    std::istringstream isb(ubound);
    while(isb >> val) {
        bpair.second = val;
    }
}

// A method to set boundary map
void Boundaries::setboundmap(std::unordered_map<std::string, 
        std::vector<std::string>> xtb) {
    for(auto s : xtb) {
        char type = s.second[1][0];
        switch(type) {
            case 'd': {
            std::pair<std::string, Boundbase*> opair;
            opair.first = s.first;
            opair.second = new Boundary<double>(
                    s.second[2], s.second[3]);
            bounds.insert(opair);
            }
            break;
            case 'i': {
            std::pair<std::string, Boundbase*> opair;
            opair.first = s.first;
            opair.second = new Boundary<int>(
                    s.second[2], s.second[3]);
            bounds.insert(opair);
            break;
            }
            case 'c': {
            std::pair<std::string, Boundbase*> opair;
            opair.first = s.first;
            opair.second = new Boundary<std::string>(
                    s.second[2], s.second[2]);
            bounds.insert(opair);
            break;
            }
        }
    }
}

यह g ++ का उपयोग करके ठीक से संकलित करता है। जब मैं इसे चलाने की कोशिश करता हूं (निम्नानुसार):

int main() {
    Data D;
    Boundaries B;
    std::ifstream iss("tphinit.txt");
    D.read_lines(iss);

    auto dbounds = D.get_xtypebound();
    B.setboundmap(dbounds);

    auto tbounds = B.getbounds();
    auto sbound = tbounds["X1"];
    std::cout << sbound->bpair.first << "," 
        << sbound->bpair.second << std::endl;
}

मुझे 'class Boundbase' has no member named 'bpair' मिलता है जो सच है क्योंकि मैं बेस क्लास की ओर इशारा कर रहा हूं न कि व्युत्पन्न वर्ग की। जहां तक ​​मैं बता सकता हूं, व्युत्पन्न सदस्य bpair प्राप्त करने का प्रयास करने के लिए यह आवश्यक है कि मैं विज़िटर पैटर्न का उपयोग करूं। अब, यह स्पष्ट है कि मैं नोब हूं इसलिए जब मैंने SO पर ऐसा करने के विभिन्न तरीकों पर एक नज़र डाली तो मैं अपने सिर पर थोड़ा सा था (लेखकों पर कोई प्रतिबिंब नहीं, बस मेरी अनुभवहीनता पर)।

तो मेरा मुख्य प्रश्न है: क्या यह इस बारे में जाने का सबसे अच्छा और सरल तरीका है? यदि संभव हो तो मैं boost::variant से बचना चाहूंगा (मुख्य रूप से शुद्धता के लिए: यह इतना मुश्किल नहीं हो सकता)। एक उप-प्रश्न यह है कि क्या मुझे विज़िटर पैटर्न का उपयोग करना है या सदस्य pbair प्राप्त करने का कोई बेहतर/सरल तरीका है?

मुझे इस लुकअप को कई बार करना होगा इसलिए मैं इसे जितनी जल्दी हो सके बनाने की उम्मीद कर रहा हूं लेकिन सादगी के लिए stl का उपयोग कर रहा हूं।

1
fatm 1 फरवरी 2021, 01:47
मुझे वह त्रुटि नहीं मिली जिसका आपने प्रश्न में उल्लेख किया है। मुझे error: 'Data' was not declared in this scope मिलता है
 – 
Ted Lyngmo
1 फरवरी 2021, 01:53
1
क्या आपने std::unordered_map<std::string, std::variant<double, int, std::string>> माना है?
 – 
Richard Critten
1 फरवरी 2021, 01:57
हाँ। ऐसा इसलिए है क्योंकि डेटा एक और वर्ग है जिसे मैंने बनाया है लेकिन इसमें शामिल नहीं है। मुझे यकीन नहीं है कि यह सवाल के लिए प्रासंगिक है या नहीं?
 – 
fatm
1 फरवरी 2021, 01:57
मुझे मूल पोस्ट में कहना चाहिए था कि मैं सी ++ 11 का उपयोग कर रहा हूं। ऐसा लगता है कि std::variant C++17 है।
 – 
fatm
1 फरवरी 2021, 01:59
1
आप या तो std::variant का उपयोग करते हैं या यह शुद्ध union जैसे घर के कार्यान्वयन में मैनुअल है, या आप विरासत का उपयोग करते हैं। std::variant क्लीनर और छोटा तरीका है।
 – 
Slava
1 फरवरी 2021, 01:59

1 उत्तर

सबसे बढ़िया उत्तर

अपने मूल्यों को ३ प्रकारों में एसटीडी वेरिएंट बनाएं।

विफल होने पर, संस्करण को बढ़ावा दें।

एसटीडी और बूस्ट वैरिएंट वास्तव में वही हैं जो आप चाहते हैं। आप इसके कार्यान्वयन के कुछ सबसेट को लागू करना समाप्त कर देंगे।

ऐसा न होने पर, उनमें से किसी को लागू करने के तरीके के बारे में एक ट्यूटोरियल खोजें, या किसी भी एसटीडी का उपयोग करें। ऐसा विफल होने पर, गतिशील एक अन्यथा बेकार रैपर प्रकार के आसपास एक अद्वितीय पीटीआर में संग्रहीत वर्चुअल डीटीओआर के साथ कास्ट करता है, या मैन्युअल आरटीटीआई को विधियों को प्राप्त करने का प्रयास करता है।

हालांकि यह तेजी से बदसूरत और/या अक्षम हो जाता है।

बूस्ट वैरिएंट, और उससे एसटीडी वैरिएंट, एक कारण से लागू किया गया था, और वह कारण उस सटीक समस्या को हल कर रहा था जिसका आप एक कुशल तरीके से वर्णन कर रहे हैं।

#include <tuple>
#include <utility>
#include <string>

template<class...Ts>
struct destroy_helper {
    std::tuple<Ts*...> data;
    destroy_helper( std::tuple<Ts*...> d ):data(d){}
    template<class T>
    static void destroy(T* t){ t->~T(); }
    template<std::size_t I>
    void operator()(std::integral_constant<std::size_t, I>)const {
        destroy( std::get<I>( data ) );
    }
};

struct construct_helper {
    template<class T, class...Args>
    void operator()(T* target, Args&&...args)const {
        ::new( (void*)target ) T(std::forward<Args>(args)...);
    }
};

template<std::size_t...Is>
struct indexes {};

template<std::size_t N, std::size_t...Is>
struct make_indexes:make_indexes<N-1, N-1, Is...> {};

template<std::size_t...Is>
struct make_indexes<0, Is...>{
    using type=indexes<Is...>;
};
template<std::size_t N>
using make_indexes_t = typename make_indexes<N>::type;

template<class F>
void magic_switch( std::size_t i, indexes<>, F&& f ) {}

template<std::size_t I0, std::size_t...Is, class F>
void magic_switch( std::size_t i, indexes<I0,Is...>, F&& f )
{
    if (i==I0) {
        f( std::integral_constant<std::size_t, I0>{} );
        return;
    }
    magic_switch( i, indexes<Is...>{}, std::forward<F>(f) );
}

template<class T0>
constexpr T0 max_of( T0 t0 ) {
    return t0;
}
template<class T0, class T1, class...Ts>
constexpr T0 max_of( T0 t0, T1 t1, Ts... ts ) {
    return (t1 > t0)?max_of(t1, ts...):max_of(t0, ts...);
}

template<class...Ts>
struct Variant{
  using Data=typename std::aligned_storage< max_of(sizeof(Ts)...), max_of(alignof(Ts)...)>::type;
  std::size_t m_index=-1;
  Data m_data;
  template<std::size_t I>
  using alternative_t=typename std::tuple_element<I, std::tuple<Ts...>>::type;
  using pointers=std::tuple<Ts*...>;
  using cpointers=std::tuple<Ts const*...>;

  template<class T> T& get(){ return *reinterpret_cast<T*>(&m_data); }
  template<class T> T const& get() const { return *reinterpret_cast<T*>(&m_data); }
  template<std::size_t I>
  alternative_t<I>& get(){ return std::get<I>(get_pointers()); }
  template<std::size_t I>
  alternative_t<I> const& get()const{ return std::get<I>(get_pointers()); }

  pointers get_pointers(){
    return pointers( (Ts*)&m_data... );
  }
  cpointers get_pointers()const{
    return cpointers( (Ts const*)&m_data... );
  }
  std::size_t alternative()const{return m_index;}

  void destroy() {
      if (m_index == -1)
        return;
      magic_switch(m_index, make_indexes_t<sizeof...(Ts)>{}, destroy_helper<Ts...>(get_pointers()));
  }

  template<std::size_t I, class...Args>
  void emplace(Args&&...args) {
      destroy();
      construct_helper{}( std::get<I>(get_pointers()), std::forward<Args>(args)... );
      m_index = I;
  }

  Variant()=default;

  Variant(Variant const&)=delete;//todo
  Variant&operator=(Variant const&)=delete;//todo
  Variant(Variant &&)=delete;//todo
  Variant&operator=(Variant &&)=delete;//todo

  ~Variant(){destroy();}
};

int main() {
    Variant<int, double, std::string> bob;
    bob.emplace<0>( 7 );
    bob.emplace<1>( 3.14 );
    bob.emplace<2>( "hello world" );
}

यहाँ वास्तव में एक सरल वैरिएंट इंटरफ़ेस है

कठिन हिस्सा रनटाइम इंडेक्स को बदल रहा है जिसमें आप किस कंपाइल टाइम इंडेक्स का उपयोग करना चाहते हैं। मैं इसे मैजिक स्विच प्रॉब्लम कहता हूं।

आप विज़िटर लागू करना भी लागू करना चाहेंगे।

...

या...

template<class T>
struct Derived;
struct Base {
  virtual ~Base() {}
  template<class T>
  friend T* get(Base* base) {
    Derived<T>* self = dynamic_cast<T*>(base);
    return self?&self.t:nullptr;
  }
  template<class T>
  friend T const* get(Base const* base) {
    Derived<T> const* self = dynamic_cast<T const*>(base);
    return self?&self.t:nullptr;
  }
};
template<class T>
struct Derived:Base {
  Derived(T in):t(std::move(in)){}
  T t;
};

std::unordered_map<std::string, std::unique_ptr<Base>> map;

map["hello"] = std::unique_ptr<Base>( new Derived<int>(-1) );
map["world"] = std::unique_ptr<Base>( new Derived<double>(3.14) );

int* phello = get<int>(map["hello"]);
if (phello) std::cout << *hello << "\n";
double* pworld = get<double>(map["world"]);
if (pworld) std::cout << *world << "\n";

जो एक गंभीर सौदेबाजी का तहखाना है std::any

4
Yakk - Adam Nevraumont 1 फरवरी 2021, 06:56
1
ओपी के समान नाव में होने के कारण, मुझे सहानुभूति हो सकती है। यदि केवल मैं वास्तव में उन उपकरणों को चुन सकता हूं जिनका मेरा संगठन उपयोग करता है। अभी भी सी ++ 14 (आईएसएच) पर नो-बूस्ट जनादेश के साथ।
 – 
WhozCraig
1 फरवरी 2021, 02:11