C++ 使用typeid处理不同的类型
我试图使用boost::any来封装sqlite返回值。然后我试着写一个循环来打印这些 我的第一个想法是:C++ 使用typeid处理不同的类型,c++,sqlite,boost,boost-any,C++,Sqlite,Boost,Boost Any,我试图使用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
for(boost::any field: row) {
switch(field.type()) {
case typeid(double):
double value = any_cast<double>(field);
...
break;
case typeid(other type):
...
}
}
for(boost::任意字段:行){
开关(field.type()){
案例类型ID(双):
双值=任何类型(字段);
...
打破
案例类型ID(其他类型):
...
}
}
现在对于有经验的程序员来说,这显然是不可行的,因为typeid返回的是一个实例而不是一个数字id。
经过一些研究,我想我可能会尝试typeid(…).hash_code()
但是这不够constexpr
合格(除了哈希冲突的危险)
问题
hash\u code
不是const\u 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);
}
#包括
#包括
#包括
使用名称空间boost;
结构Nil{};
使用blob_t=std::vector;
使用字段\u值\u t=boost::variant;
结构处理程序:静态\u访问者{
std::string操作符()(double)const{return“double”;}
std::string operator()(char const*)const{return“C string(ew!)”;}
std::string操作符()(long)const{return“long”;}
std::string操作符()(blob_t)const{return“long”;}
std::string操作符()(Nil)常量{return”“;}
模板
std::string操作符()(T const&)const{throw“未实现”}//TODO正确异常
};
无效句柄字段(字段值常量和值){
std::cout这里是一个类似于boost::any上的静态访问的实现,使用C++11 lambdas:
#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\u调用的第一个参数,然后传递多个lambda。将调用参数类型与boost::any
中包含的对象类型匹配的第一个lambda,然后any\u调用将返回true。如果没有lambda匹配,任何调用
都将返回false。不会typeid(field)
只返回boost::any
?hash\u code()的类型ID
不是constexpr
,因为type\u info
可能是多态的。有人讨论过提出一种获取类型编译时标识符的方法,但我认为它没有用?使用std::map将type\u索引映射到函子。我将把这项技术留在这里,我指的是“computed goto”是编译switch
的可能方式之一。它使用跳转表,控制变量是用来查找表中的条目的。如果生成的跳转表不够密集,编译器可以选择使用一系列条件编译switch语句(与if/else完全相同)。()boost::varaint
比boost::any
的优势在哪里?标记null
值的最佳方法是什么?(将void*
添加到模板参数?@ted为什么void*
?它不再是C:)struct Nil{};boost::variant
您已经上路了。更新了示例哦,re优势在哪里
:优势在于您将类型区分留给boost variant,而不会离开类型安全,也不会处理围绕typeid的潜在毛羽。
#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;
}