C++ Class for Boxing & Unboxing

Viewed 1207

I want to have a class Boxed_value that can InBox other types (starting from int, double, string...), similar to object in C#. This class type can be further passed to functions that Unbox it. These functions will receive a reference:

void receiver( Boxed_value & bv ) {}

So, it shouldn't be a template. Or? I need a recipe... The UnBox function can be separate, and templated. In this case receiver can get 2 parameters:

void receiver( Boxed_value & bv, Engine & eng ) {}

The implementation below is dummy and it's not compiling.

struct Boxed_value {
    void inbox(int v) { _iv = v; }
    void inbox(double v) { _dv = v; }
    void inbox(std::string & v) { _sv = v; }

    int _iv;
    double _dv;
    std::string _sv;
};

struct Engine {
    template<typename T>
    T unbox(Boxed_value bv) { 
        if (std::is_same<T, typeid(bv._iv).name()>::value) { return _iv };
        if (std::is_same<T, typeid(bv._dv).name()>::value) { return _dv };
        if (std::is_same<T, typeid(bv._sv).name()>::value) { return _sv };
    }
};
1 Answers
  1. Note that at compile-time, every if clause has to be instantiated; that means you're returning different types in function unbox.

  2. You should compare the type of members in std::is_same, but not sth like typeid(bv._iv).name(), which is not type but an object with type const char*.

You can apply Constexpr If (since C++17).

If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.

And use decltype (since C++11) to get type of the members.

e.g.

template<typename T>
T unbox(const Boxed_value& bv) { 
    if constexpr (std::is_same<T, decltype(bv._iv)>::value) { return bv._iv };
    else if constexpr (std::is_same<T, decltype(bv._dv)>::value) { return bv._dv };
    else if constexpr (std::is_same<T, decltype(bv._sv)>::value) { return bv._sv };
}

Before C++17, you can apply full specialization.

template<typename T>
T unbox(const Boxed_value& bv);

template<>
decltype(Boxed_value::_iv) unbox<decltype(Boxed_value::_iv)> (const Boxed_value& bv) { return bv._iv; }
template<>
decltype(Boxed_value::_dv) unbox<decltype(Boxed_value::_dv)> (const Boxed_value& bv) { return bv._dv; }
template<>
decltype(Boxed_value::_sv) unbox<decltype(Boxed_value::_sv)> (const Boxed_value& bv) { return bv._sv; }

PS: I changed the parameter type from Boxed_value to const Boxed_value&, to avoid unnecessary copy.

Related