0

For weeks I've been searching the internet about heterogeneous lists (vector, array, list) in c++, however, in all sites and forums, the answer is the same: boost::any, but I wanted a way to do it in pure C ++. I developed this:

#include <iostream>
#include <typeinfo>
#include <vector>

using namespace std; 
 //Compiler version g++ 6.3.0

 class any
 {
 public:
    auto get() {}
 };

 template<typename T>
 class anyTyped : public any
 {
 public:
    T val;

    anyTyped(T x)
    {
        val = x;
    }
    T get()
    {
        return val;
    }
 };

 class queue
 {
    vector<any*> x;
    int len = 0;

 public:
    queue()
    {
        x.resize(0);
    }

    template<typename T>
    void insert(T val)
    {
        any* ins = new anyTyped<T>(val);
        x.push_back(ins);
        len++;
    }
    int size()
    {
        return len;
    }

    auto& at(int idx)
    {
        return x[idx]->get();
    }
 };

 int main()
 {

    queue vec;

    vec.insert(5);     //int
    vec.insert(4.3);   //float
    vec.insert("txt"); //string

    for (int i = 0; i < vec.size(); i++)
    {
        cout << vec.at(i);
    }

    return 0;
 }

But i get the this error:

source_file.cpp: In member function 'auto& queue::at(int)':
source_file.cpp:55:23: error: forming reference to void
    return x[idx]->get();
                       ^
source_file.cpp: In function 'int main()':
source_file.cpp:70:9: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'void')
    cout << vec.at(i);
    ~~~~~^~~~~~~~~~~~

I know the problem is in using auto as the return type, either in auto get() in the any class, or in auto& at(int idx) in the queue class, but I don't know how to fix.

Felipe Nascimento
  • 207
  • 1
  • 4
  • 10
  • In C++ 17, std::any has been added. – Russley Shaw Jul 18 '17 at 20:19
  • 1
    In my experience, creating your own "any" class is very difficult and non-intuitive so much so that the only popular implementation has been historically Boost and more recently C++17. I'd recommend you try not to reinvent the wheel unless you have a specific reason to. I'd also recommend you make an attempt to use something like std::variant rather than any because the more knowledge you have of your types, the better. – Russley Shaw Jul 18 '17 at 20:28
  • `boost::any` **is** pure C++. Also what do you expect `auto get() {}` to do? It cannot deduce the type for `auto` and it doesn't return anything. – nwp Jul 18 '17 at 20:28
  • @nwp I'm assuming he meant without importing a library as large as Boost. – Russley Shaw Jul 18 '17 at 20:29
  • @nwp, `auto get() {}` is just to implement `T get()` after. – Felipe Nascimento Jul 18 '17 at 20:40
  • @RussleyShaw look, I searched about this. According to [this site](https://stackoverflow.com/documentation/c%2b%2b/7894/stdany#t=201707182058315256938), I need to use `std::any_cast(std::any& operand)` to call the value in `operand`. The problem keep the same: I need to say the data type to use the value. – Felipe Nascimento Jul 18 '17 at 21:28
  • Eventually, yes you would need to specify what type you wish to pull out of your container. The best way would be to template your `queue.at` function so that you can specify the type. Example: `queue.at()`. – Russley Shaw Jul 18 '17 at 21:32
  • C++ is not a dynamic language despite it maybe looking that way with great additions to the language such as std::any and auto. – Russley Shaw Jul 18 '17 at 21:33
  • @RussleyShaw There's any way to store the data type in a variable? – Felipe Nascimento Jul 18 '17 at 21:40

2 Answers2

1

In order to be stored, all heterogenous data must be brought down to something homogeneous in C++. std::any is no exception. To make things homogeneous there are, most importantly, inheritance and type erasure (any is an instance of the latter).

Applied to your example, this could mean, for example, that you have to specify the return type of get to a fixed type. In the best case, this would be the std::common_type of all your used types T.

To get the idea:

anyTyped<double> anyDouble{1.0};
anyTyped<int> anyInt{2};

std::vector<std::function<double()> > anyStore;  //the chosen homogenous type is 'double'

//get() should be const, otherwise add a 'mutable'
anyStore.push_back([anyDouble]() { return anyDouble.get(); });
anyStore.push_back([anyInt]() { return anyInt.get(); });

You can now call

auto x = anyStore[0]();   //x is a double
x = anyStore[1]();

You get a double in both cases, but you wont get back your int.

All runtime dealing with heterogenous builds on a similar principle, but might be more sophisticated -- which basically means that more layers are involved until the chain ends in an homogenous type.

davidhigh
  • 14,652
  • 2
  • 44
  • 75
0

There is something inherently flawed with your any class and I'd recommend you address these issues before adding it into a queue.

The main issue is that C++ is a statically typed language and pulling out values from vec.at(i) will most likely require some sort of typing information: vec.at<int>(i).

Your any implementation is going to be much more robust and smarter to work the way you intend. Use boost/any.hpp or std::any. If you don't want to include the entirety of boost, try including just the any header or finding a single header implementation of an any library.

In your case, there is going to be nothing really special about your queue implementation because the heterogeneity will be contained within the any type.

If you really wish to implement your own, look at the implementation boost has and see if you can derive from it. Its not going to be as simple as what you might expect from dynamically typed language.

http://www.boost.org/doc/libs/1_55_0/boost/any.hpp

At the end of the day, you are going to need to specify the data type you wish to extract from your any class.

Russley Shaw
  • 441
  • 2
  • 9