使用 typeid 来处理不同的类型
Use of typeid to handle different types
我正在尝试使用 boost::any 来封装 sqlite 返回值。然后我尝试编写一个循环来打印这些。
我的第一个想法是做这样的事情:
for(boost::any field: row) {
switch(field.type()) {
case typeid(double):
double value = any_cast<double>(field);
...
break;
case typeid(other type):
...
}
}
现在对于有经验的程序员来说,很明显这是行不通的,因为 typeid 返回的是实例而不是数字 id。经过一些研究,我想我可能会尝试任何一种typeid(...).hash_code()
但这还不够constexpr
合格(除了哈希碰撞的危险)。
问题
- 有没有比构建过多的
if ... else ...
迷宫更好的方法来根据对象的类型来处理对象? hash_code
不是const_expr
有什么原因吗?这是单独编译目标文件的结果吗?std::type_index
有什么用?考虑到它只提供了一些额外的运算符(<
、<=
、>
、>=
),为什么不能将其功能与std::type_info
集成?
我有一种感觉,你正在寻找提升变体和静态访问。
由于没有提到变体,这可能值得作为答案发布。演示:
住在科里鲁
#include <sstream>
#include <iostream>
#include <boost/variant.hpp>
using namespace boost;
struct Nil {};
using blob_t = std::vector<uint8_t>;
using field_value_t = boost::variant<Nil, double, char const*, long, blob_t/*, boost::date_time, std::vector<uint8_t>*/>;
struct handler : static_visitor<std::string> {
std::string operator()(double) const { return "double"; }
std::string operator()(char const*) const { return "C string (ew!)"; }
std::string operator()(long) const { return "long"; }
std::string operator()(blob_t) const { return "long"; }
std::string operator()(Nil) const { return "<NIL>"; }
template<typename T>
std::string operator()(T const&) const { throw "Not implemented"; } // TODO proper exception
};
void handle_field(field_value_t const& value) {
std::cout << "It's a " << apply_visitor(handler(), value) << "n";
}
int main() {
handle_field({});
handle_field(blob_t { 1,2,3 });
handle_field("Hello world");
handle_field(3.14);
}
指纹
It's a <NIL>
It's a long
It's a C string (ew!)
It's a double
下面是一个类似于 boost::any
上的静态访问的实现,使用 C++11 lambda:
#include <iostream>
#include <type_traits>
#include <boost/any.hpp>
template <size_t, typename...>
struct select_type { };
template <size_t index, typename First, typename... Types>
struct select_type<index, First, Types...> : public select_type<index - 1, Types...> { };
template <typename First, typename... Types>
struct select_type<0, First, Types...>
{
using type = First;
};
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())> { };
template <typename Return, typename Class, typename... Args>
struct function_traits<Return (Class::*)(Args...) const>
{
using result_type = Return;
template <size_t argN>
using argument_type = select_type<argN, Args...>;
};
template <typename... Functors>
struct any_call_impl
{
static bool call(boost::any &, Functors const & ...)
{
return false;
}
static bool call(boost::any const &, Functors const & ...)
{
return false;
}
};
template <typename FirstFunctor, typename... Functors>
struct any_call_impl<FirstFunctor, Functors...>
{
static bool call(boost::any & v, FirstFunctor const & first, Functors const & ... rest)
{
using arg = typename function_traits<FirstFunctor>::template argument_type<0>::type;
using arg_bare = typename std::remove_cv<typename std::remove_reference<arg>::type>::type;
if (v.type() == typeid(arg_bare)) {
first(*boost::any_cast<arg_bare>(&v));
return true;
}
return any_call_impl<Functors...>::call(v, rest...);
}
static bool call(boost::any const & v, FirstFunctor const & first, Functors const & ... rest)
{
using arg = typename function_traits<FirstFunctor>::template argument_type<0>::type;
using arg_bare = typename std::remove_cv<typename std::remove_reference<arg>::type>::type;
if (v.type() == typeid(arg_bare)) {
first(*boost::any_cast<arg_bare>(&v));
return true;
}
return any_call_impl<Functors...>::call(v, rest...);
}
};
template <typename... Functors>
bool any_call(boost::any & v, Functors const & ... f)
{
return any_call_impl<Functors...>::call(v, f...);
}
template <typename... Functors>
bool any_call(boost::any const & v, Functors const & ... f)
{
return any_call_impl<Functors...>::call(v, f...);
}
int main(void) {
boost::any a = 1;
any_call(a,
[](double d) { std::cout << "double " << d << std::endl; },
[](int i) { std::cout << "int " << i << std::endl; }
);
return 0;
}
(演示)
这个想法是你传递一个boost::any
或boost::any const
作为any_call
的第一个参数,然后你传递多个lambda。 将调用参数类型与 boost::any
中包含的对象类型匹配的第一个 lambda,然后any_call
将返回 true。 如果没有 lambda 匹配,any_call
将返回 false。
相关文章:
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 在运行时处理类型擦除的数据-如何不重新发明轮子
- 为什么 GCC 在使用类型别名时处理 const reinterpret_cast不同?
- 像union_这样的 Boost.Geometry 操作如何处理浮点类型的基本不精确性?
- 模板函数如何处理可能共享一个交集的多个类型名称?
- 设计帮助 - 为不同类型的消息处理通用接口的设计模式
- 在自定义 std::vector-like 容器中处理指针和非指针模板类型的最佳方法是什么?
- 如何处理模板类中的复合类型
- C++在一个映射中存储不同的指针类型(并处理销毁)
- 如何在C库中处理与C++不同大小的类型
- 如何处理具有无效数据类型的异常
- 处理一般情况混合类型和非类型的可变参数模板
- 类型不可知的抽象以使用相同的运行时接口处理正向和反向迭代器和范围?
- 如何在Boost::program_options配置文件中为非字符串的自定义选项值类型处理空格
- 我可以让返回类型自动处理具有相同签名但捕获不同内容的 lambda 吗?
- 如何处理高于 7FF.. 64 位和uint64_t类型的十六进制值
- 当 C++ 中函数参数的输入类型(类)错误时的错误处理
- 如何处理C++98中不同类型的多个参数?
- 如何使用void类型处理递归回溯返回
- 扩展Visual Studio(2010+)项目类型处理程序