Casting std::any to std::tuple

71 views Asked by At

I'm having this piece of code...

class TableModel {
 public:
  TableModel(std::vector<std::string> header = {},
                 std::string tableName = "")
      : header_(header.begin(), header.end()),
        tableName_(tableName) {}

  std::vector<std::string> header() { return header_; }

  size_t columns() { return header_.size(); }

  size_t rows() { return rows_.size(); }
  
  template <typename... Args>
  auto cell(const size_t row, const size_t col){
      if(row < 0 or row > rows()){
          throw std::out_of_range("Invalid row index value");
      }
      auto t = rows_[row]; // first issue

      /*Here it returns a std::any but it should be a std::tuple data type*/
      /*once cast done, it should return the value in the col position. but*/
      
      return get<col>(t); //second issue
      /*it is not working due get function is quite special*/
  }

  /*This works as a charm*/
  template <typename... Args>
  void addRow(Args &&...args) {
    rows_.emplace_back(std::tuple(std::forward<Args>(args)...));
  }

 private:
  std::vector<std::string> header_;
  std::string tableName_;
  std::vector<std::any> rows_; // root of problems
};

I want to do it quite interesting, and not doing a Array or a vector of vectors (or related). I don't know if you can help me casting from std::any to std::tuple and once done, get the data in the tuple according to the desired position.

I've tried declaring the row as tuple of strings with variadic parameter, but does not work std::vector<std::tuple<std::string...>> rows_;

Thank you so much

1

There are 1 answers

0
Keyboard Corporation On BEST ANSWER

std::tuple is not designed to work with variadic templates in the way you're trying to use them.

In your code, std::tuple<std::string...> is not valid because std::tuple expects a fixed number of type arguments, not a variable number of arguments. This is why you're getting an error when you try to declare std::vector<std::tuple<std::string...>> rows_;

If you want to store a tuple of strings, you can declare std::tuple<std::string, std::string, ...> rows_; where you replace ... with the number of strings you want to store. However, this is not very flexible because you need to know the number of strings at compile time.

A better approach might be to use of std::vector<std::string> to store the strings in each row. This allows you to store a variable number of strings in each row.

I modify your TableModel class to this approach;

class TableModel {
 public:
 TableModel(std::vector<std::string> header = {},
                std::string tableName = "")
     : header_(header.begin(), header.end()),
       tableName_(tableName) {}

 std::vector<std::string> header() { return header_; }

 size_t columns() { return header_.size(); }

 size_t rows() { return rows_.size(); }
 
 std::string cell(const size_t row, const size_t col){
     if(row < 0 or row > rows()){
         throw std::out_of_range("Invalid row index value");
     }
     return rows_[row][col];
 }

 template <typename... Args>
 void addRow(Args &&...args) {
   rows_.emplace_back(std::vector<std::string>{std::forward<Args>(args)...});
 }

 private:
 std::vector<std::string> header_;
 std::string tableName_;
 std::vector<std::vector<std::string>> rows_;
};

In the above code, rows_ is a vector of vectors of strings. Each inner vector represents a row in the table, and each string in the inner vector represents a cell in the row. The cell function returns the string in the specified cell. The addRow function adds a new row to the table.

This approach is more flexible than using std::tuple because it allows you to store a variable number of strings in each row. However, it does require you to manage a vector of vectors, which can be more complex than using a single vector.