如何在 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
变量。
我想用 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
变量。