Home > Back-end >  How to deduce a return type in C
How to deduce a return type in C

Time:03-17

I want to create some kind of Variant in C . Actually I want to use templates as less as possible. The idea is to store the value in union both with the type of the variable and return the value according to the stored type.

So the test code looks like following:

#include <iostream>
#include <vector>
#include <cstring>
#include <typeinfo>
#include <typeindex>

using namespace std;

constexpr uint64_t mix(char m, uint64_t s)
{
    return ((s << 7)   ~(s >> 3))   static_cast<uint64_t>(~m);
}

constexpr uint64_t _(const char* str)
{
    return (*str) ? mix(*str,_(str   1)) : 0;
}

class Variant
{
public:
    template<typename T>
    Variant(T value):
        m_info(typeid(value))
    {
        std::memcpy(&m_val, &value, sizeof(T));
    }

    auto toValue() ->decltype(???) // what have I use here ???
    {
        switch(_(m_info.name()))
        {
            case _("b"):
                return m_val.bval;
            case _("i"):
                return m_val.ival;
            case _("d"):
                return m_val.dval;
            break;
        }

        return 0;
    }
    char cval;
    unsigned char ucval;

private:
    union Types
    {
        bool bval;
        int ival;
        double dval;
    } m_val;
    std::type_index m_info;
};

Usage:

int main()
{
    std::vector<Variant> arr = { 1, 2.2, true };
    for(auto &v: arr)
    {
        cout << "value is: " << v.toValue() << endl;
    }
    return 0;
}

But decltype requires an expression as a parameter and that's where I'm stuck. What expression have I use here?

CodePudding user response:

As per @UnholySheep's comment, what you're trying to do is have a function whose return type is deduced at runtime, which is simply not possible. The return type has to be known at compile time. So you're going to have to change your API. There are a few different options here.

This seems similar to std::variant, whose API equivalent to your toValue() looks like this:

std::get<double>(variant)
std::get<int>(variant)
std::get<bool>(variant)

This function call std::get will throw std::bad_variant_access if you try to get the value with the wrong type. You could do that here.

Another option is to extract the union { bool, int, double } type out of the Variant class so you can use it as the return type. Then it'd probably be advisable to have another function call so the caller can tell at runtime which type the union actually is. You could return an enum or just return your m_type variable for this.

  • Related