3

I recently started to use Boost C++ library and I am testing the any class which can hold any data type. Actually I am trying to define the operator<< to print easily the content of any variable of type any (and sure, the class of the content should have the operator<< defined too). I only started by sample types ( int, double ...) because they have be displayed by default. And till now, I have this code :

#include <boost/any.hpp>
#include <iostream>
#include <string>
using namespace std;
using namespace boost;

ostream& operator<<(ostream& out, any& a){
    if(a.type() == typeid(int))
        out << any_cast<int>(a);
    else if(a.type() == typeid(double))
        out << any_cast<double>(a);
    // else ...
    // But what about other types/classes ?!
}

int main(){
    any a = 5;
    cout << a << endl;
}

So the problem here is that I have to enumerate all possible types. Is there any way to cast the variable to a particular type having the type_info of this particular type ?

webNeat
  • 2,768
  • 1
  • 20
  • 22
  • 1
    You cannot enumerate "all possible types". The type is called *any*, not *every*. – Kerrek SB Oct 09 '14 at 00:07
  • Maybe you could use [Boost type erasure](http://www.boost.org/doc/libs/1_55_0/doc/html/boost_typeerasure.html) for more specific type erasure needs. As it stands, the question is confusing because the title is about casting (which is probably wrong or ill-advised), whereas the body is about formatting, which is a well-understood and rather different problem. – Kerrek SB Oct 09 '14 at 00:08
  • I have never used `boost::any` and I have written some pretty bizarre code. You don't need to use it either. It's uses are _incredibly_ few. – Mooing Duck Oct 09 '14 at 00:12
  • @KerrekSB : My main problem is about formatting, but in order to solve it; I have to cast the `any` instance to corresponding type ! – webNeat Oct 09 '14 at 00:14
  • @MooingDuck : As I said, I am just testing this library and just wondering if what I am trying to do is actually possible somehow or not – webNeat Oct 09 '14 at 00:19
  • @webNeat: You've erased the type. This is only doable if you also erase the corresponding `operator<<` at the same time. – Mooing Duck Oct 09 '14 at 00:22
  • 3
    @webNeat: That sounds like a classic X-Y problem. – Kerrek SB Oct 09 '14 at 00:23
  • I don't think a general solution it is possible. There is no way in runtime to check does a type support stream operator and call it appropriately. All you can do is check and enumerate all supported types. – Bryan Chen Oct 09 '14 at 00:29
  • 4
    @BryanChen: You can erase the `operator<<` at the same time `boost::any` erases the data: http://coliru.stacked-crooked.com/a/de70c25df7302c7f, but it's quite the hack. – Mooing Duck Oct 09 '14 at 00:32
  • @MooingDuck : Thank you. this hack do the trick :) – webNeat Oct 09 '14 at 01:13

1 Answers1

1

Boost.Any any

With boost::any you cannot do that as others have already noted in comments. That is because boost::any forgets everything about the type of value it stores and requires you to know what type is there. While you have no way to enumerate every possible type.

The solution is to change boost::any so that it forgets everything about the type of value it stores except for how to stream it out. Mooing Duck provided one solution in comments. Another would be to write a new version of boost::any but extend its internals to support the streaming operation.

Boost.Spirit hold_any

Boost.Spirit already provides something like that in <boost/spirit/home/support/detail/hold_any.hpp>.

Boost.TypeErasure any

A far better approach is however to use Boost.TypeErasure's any as was mentioned by Kerrek SB in his comment.

An example for your case (use of <<) would look like this:

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/operators.hpp>
#include <iostream>
#include <string>

int main() {
    typedef
        boost::type_erasure::any<
            boost::mpl::vector<
                boost::type_erasure::destructible<>,
                boost::type_erasure::ostreamable<>,
                boost::type_erasure::relaxed
            >
        > my_any_type;

    my_any_type my_any;

    my_any = 5;
    std::cout << my_any << std::endl;
    my_any = 5.4;
    std::cout << my_any << std::endl;
    my_any = std::string("text");
    std::cout << my_any << std::endl;
}
Adam Badura
  • 5,069
  • 1
  • 35
  • 70