如何在 C++ 中推导出 return 类型

How to deduce a return type in C++

我想用 C++ 创建某种 Variant。其实我想尽量少用模板。这个想法是将值存储在 union 中,同时使用变量类型和 return 根据存储类型存储值。

因此测试代码如下所示:

#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;
};

用法:

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

但是 decltype 需要一个表达式作为参数,这就是我遇到的问题。我在这里用了什么表达方式?

根据@UnholySheep 的评论,您想要做的是拥有一个 return 类型在运行时推导的函数,这根本不可能。 return 类型必须在编译时已知。所以你将不得不改变你的API。这里有几个不同的选项。

这似乎类似于 std::variant,其 API 相当于您的 toValue() 看起来像这样:

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

如果您尝试获取错误类型的值,此函数调用 std::get 将抛出 std::bad_variant_access。你可以在这里做。

另一种选择是从 Variant class 中提取 union { bool, int, double } 类型,这样您就可以将其用作 return 类型。然后可能建议进行另一个函数调用,以便调用者可以在运行时告诉联合实际上是哪种类型。你可以 return 一个枚举或者只是 return 你的 m_type 变量。