0

I have different data types which I'm trying to save in one HashMap.

The HashMap will be created inside a variable arguments function.

Unions under struct and Boost::Any didn't work for me,
Unions don't accept classes as data types. Boost::any gives me errors while I go through the varargs.

Any suggestions?

Please tell me if I should give more details.

Code with boost::any

#include <iostream>
#include <string>
#include <cstdarg>
#include <boost/any.hpp>
#include <boost/variant.hpp>

class vec3D{
 public:
    int x;
    vec3D(int p){ x=p;}
 };

using namespace std;

struct testing{
    enum Type {U32, U64, I32, I64, D, S, B, ENDNOW};
    Type val;
    boost::any Point;

};

void mandatory(int count...){
    va_list args;
    va_start(args, count);
    testing tester;
    for ( tester.val=va_arg(args, testing::Type) ; tester.val != testing::ENDNOW ; tester.val=va_arg(args, testing::Type) ){
    //for (testing tester.val = va_arg(args, testing->Type); tester.val != 11; tester=va_arg(args, testing->Type) ){
        switch(tester.val) {
            case 0: cout<< "u32"; tester.Point = va_arg(args, uint32_t); break;
            case 1: cout<< "u64"; tester.Point = va_arg(args, uint64_t); break;
            case 2: cout<< "32"; tester.Point = va_arg(args, int32_t); break;
            case 3: cout<< "64"; tester.Point = va_arg(args, int64_t); break;
            case 4: cout<< "double"; tester.Point = va_arg(args, double); break;
            //case 5: cout<< "string"; tester.Point = va_arg(args, string); break;
            case 6: cout<< "boolean"; tester.Point = va_arg(args, bool); break;
            case 7: cout<< "EndNow"; break;
            default: break; //this is the end now.
        }
        cout<<'\t'<<tester.Point<<endl;
    }
    va_end(args);
    cout<<endl;
}

int main(){
    mandatory(12, testing::U32, 99, testing::B, 0, testing::D,11E1, testing::I64,5000000, testing::ENDNOW);
    return 0;
}

Code with boost::variant

#include <iostream>
#include <string>
#include <cstdarg>
#include <boost/any.hpp>
#include <boost/variant.hpp>

class vec3D{
 public:
    int x;
    vec3D(int p){ x=p;}
 };

using namespace std;

struct testing{
    enum Type {U32, U64, I32, I64, D, S, B, ENDNOW};
    Type val;
    typedef boost::variant<uint32_t, uint64_t, int32_t, int64_t, double, string, bool, vec3D> point;
    point Point;

};

void mandatory(int count...){
    va_list args;
    va_start(args, count);
    testing tester;
    for ( tester.val=va_arg(args, testing::Type) ; tester.val != testing::ENDNOW ; tester.val=va_arg(args, testing::Type) ){
        switch(tester.val) {
            case 0: cout<< "u32"; tester.Point = va_arg(args, uint32_t); break;
            case 1: cout<< "u64"; tester.Point = va_arg(args, uint64_t); break;
            case 2: cout<< "32"; tester.Point = va_arg(args, int32_t); break;
            case 3: cout<< "64"; tester.Point = va_arg(args, int64_t); break;
            case 4: cout<< "double"; tester.Point = va_arg(args, double); break;
            //case 5: cout<< "string"; tester.Point = va_arg(args, string); break;
            case 6: cout<< "boolean"; tester.Point = va_arg(args, bool); break;
            case 7: cout<< "EndNow"; break;
            default: break; //this is the end now.
        }
        cout<<'\t'<<tester.Point<<endl;
    }
    va_end(args);
    cout<<endl;
}

int main(){
    mandatory(12, testing::U32, 99, testing::B, 0, testing::D,11E1, testing::I64,5000000, testing::ENDNOW);
    return 0;
}
sudhansh_
  • 125
  • 1
  • 2
  • 14
  • Do you need to support any type or just a set of types? If it's the latter consider using boost/std variant. – NathanOliver Jun 01 '17 at 19:28
  • @NathanOliver that didn't work with user defined classes. – sudhansh_ Jun 01 '17 at 19:39
  • 1
    Define "didn't work". `any`/`variant` sounds like what you need. If you can't get it working you can always post a [mcve] and ask for help in fixing it. – NathanOliver Jun 01 '17 at 19:40
  • I got a compilation error when I added a class to the variant types. `error: invalid operands to binary expression ('std::__1::basic_ostream' and 'const vec3D')` – sudhansh_ Jun 01 '17 at 19:46
  • You should definitely post your code, or at least whichever chunk of it is relevant to this question. – Jayson Boubin Jun 01 '17 at 19:49
  • Do you really need to use `va_args`? If you use variadic templates the types will be preserved – Steve Lorimer Jun 01 '17 at 20:06
  • @SteveLorimer yes I do. Like mandatory(), I will have another function called optional(). Both have 10 parameters in all, and the user will define what is mandatory and what is optional. – sudhansh_ Jun 01 '17 at 20:17
  • I think perhaps you don't understand the similarities between `va_args` and variadic templates. The [answer below](https://stackoverflow.com/a/44316355/955273) uses variadic templates instead of `va_args`, and can consume any number of arguments passed to it – Steve Lorimer Jun 01 '17 at 20:19

1 Answers1

1

With variant, it could be:

#include <iostream>
#include <string>
#include <variant>
#include <vector>

class vec3D{
 public:
    int x;
    vec3D(int p){ x=p;}
 };

struct testing{
    using point = std::variant<std::uint32_t, std::uint64_t, std::int32_t,
                               std::int64_t, double, std::string, bool, vec3D>;
    point Point;
};

struct Visitor
{
    void operator() (std::uint32_t) const { std::cout << "u32" << std::endl; }
    void operator() (std::uint64_t) const { std::cout << "u64" << std::endl; }
    void operator() (std::int32_t) const { std::cout << "32" << std::endl; }
    void operator() (std::int64_t) const { std::cout << "64" << std::endl; }
    void operator() (double) const { std::cout << "double" << std::endl; }
    void operator() (const std::string&) const { std::cout << "string" << std::endl; }
    void operator() (bool) const { std::cout << "bool" << std::endl; }
    void operator() (const vec3D&) const { std::cout << "Vec3D" << std::endl; }
};

template <typename ... Ts>
void mandatory(Ts ... args){
    std::vector<testing> testings;

    (std::visit(Visitor{}, testing::point(args)), ...);
    (testings.push_back({args}), ...);
}

int main(){
    mandatory(std::uint32_t(99u), false, 11.42,
              std::int64_t(5000000), std::string("Hello world"), vec3D{42});
}

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302