dimanche 31 janvier 2021

An unordered_map that returns pairs of different types c++

I am trying to implement an std::unordered_map that returns pairs of either double, int or std::string. The keys for the map are std::strings. Below is what I have tried so far:

#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;
            }
        }
    }
}

This compiles ok using g++. When I try to run it though ( as follows):

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;
}

I get 'class Boundbase' has no member named 'bpair' which is true because I am pointing to the base class and not the derived class. As far as I can tell, trying to get the derived member bpair requires that I use the visitor pattern. Now, it is clear that I am noob so when I had a look at different ways of doing this on SO I was a little in over my head (no reflection on the authors, just on my inexperience).

So my main question is: Is this the best and simplest way to go about this? I would like to avoid boost::variant if at all possible (mainly for the sake of purity: this cannot be that difficult). A sub-question is whether I have to use the visitor pattern or is there a better/simpler way to get the member pbair?

I will have to perform this lookup many times so I am hoping to make it as fast as possible but using the stl for the sake of simplicity.

Aucun commentaire:

Enregistrer un commentaire