简体   繁体   中英

How to print elements of a std::vector<std::any> vector in C++?

The system is able to figure out the type of each element using a.type().name() but seriously is not able to print them?

#include <iostream>
#include <vector>
#include <any>
#include <string>
#include <algorithm>
    
template<typename Last>
void addElement(std::vector<std::any>& container, Last last) {
    std::cout << "Last = " << last << std::endl;
    container.push_back(last);
}

template<typename First, typename... Rest>
void addElement(std::vector<std::any>& container, First first, Rest... rest) {
    std::cout << "Elem = " << first << std::endl;
    container.push_back(first);
    addElement(container, rest...);
}

template<typename... Ts>
std::vector<std::any> createAnyVector(Ts... ts) {
    std::vector<std::any> container;
    addElement(container, ts...);
    return container;
}

int main() {
    std::cout << "ANYVECTOR" << std::endl;

    std::vector<std::any> container = createAnyVector("Hello", 3.14, 'A', true, 42);

    std::cout << "Number of elements in container = " << container.size() << std::endl; // 5 correct.

    for (const auto& a : container) {

        std::cout << a.type().name() << ", " << "HERE?" << std::endl;
    }
}

If I just write a at the place where now HERE? stands, it returns the error:

No operator << matches these operands
operand types are: std::basic_ostream<char, std::char_traits<char>> << const << std::any

As the comments point out, you cannot do anything directly with std::any , you can just hold them.

If you control the API and have the option to create a wrapper around std::any , you can maintain a function pointer to print the current std::any 's contents like so:

struct printable_any {
  template <class T>
  printable_any(T&& t) : m_val(std::forward<T>(t)) {
    m_print_fn = [](std::ostream& os, const std::any& val) {
      os << std::any_cast<std::decay_t<T>>(val);
    };
  }

private:
  using print_fn_t = void(*)(std::ostream&, const std::any&);
  std::any m_val;
  print_fn_t m_print_fn;
  
  friend std::ostream& operator<<(std::ostream& os, const printable_any& val) {
    val.m_print_fn(os, val.m_val);
    return os;
  }
};

Note that even with this, you cannot take a random std::any and print it, you have to construct it yourself along with the function pointer.

Usage:

int main() {
    std::vector<printable_any> vals {
        "Hello", 3.14, 'A', true, 42
    };

    for (auto& v : vals) {
        std::cout << v << '\n';
    }
}

Prints

Hello
3.14
A
1
42

https://godbolt.org/z/o1sejrv1e

Well, what would this print:

struct Foo {
  void *p;
};

any v = Foo{};
cout << v << '\n'; // what should this print?

There is no toString equivalent in C++. If you want that behavior, you may create your own hierarchy:

struct Printable {
    virtual void print(ostream&) const = 0;
};

auto& operator<<(ostream& os, any const& obj) {
    any_cast<Printable const&>(obj).print(os);
    return os;
}

Or customize it as you wish and handle the error cases as you like, also add special cases for the integer types if you want, etc.

Does the vector have to be of type any or are you allowed to at least specify the kind of types that are stored in the vector? Because if you can at least specify which types are allowed, I recommend using std::variant . example: std::vector<variant<int, string>> myVectorVariant ;

After that, you can actually print to the console the items in your vector through the use of std::get_if from std::variant. copy-able function below to output your vector for the most of the main primitive types: int, float, char, string.

#include <variant>
#include <vector>
#include <iostream>
using namespace std;

void printVectorVariantValues(vector<variant<int, float, char, string>> arg) {
  try {
      for (auto val : arg) {
          if (const auto intPtr (get_if<int>(&val)); intPtr) 
              cout << *intPtr << " ";
          else if (const auto floatPtr (get_if<float>(&val)); floatPtr)
              cout << *floatPtr << " ";
          else if (const auto charPtr (get_if<char>(&val)); charPtr)
              cout << *charPtr <<  " ";
          else if (const auto stringPtr (get_if<string>(&val)); stringPtr) 
              cout << *stringPtr << " ";
      }    
  } catch (bad_variant_access err) {
      cout << "something" << " ";
  }
  
  cout << "DONE" << endl;
}

int main() {
    vector<variant<int, float, char, string>> myVectorVariant = {1, 2, 'a', 'b', 3, 0.4f, 0.5f, "c", "DeF", 0.6f, "gHi", "JkL" };
    printVectorVariantValues(myVectorVariant);
    return 0;
}

/* 
output below: 
1 2 a b 3 0.4 0.5 c DeF 0.6 gHi JkL DONE
*/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM