Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I am trying to use boost::any to encapsulate the sqlite return values. I then tried to write a loop to print these.
My first thought was to do something like:
for(boost::any field: row) {
switch(field.type()) {
case typeid(double):
double value = any_cast<double>(field);
break;
case typeid(other type):
Now for the experienced programmer it becomes obvious that this can not work since typeid returns an instance rather than a numeric id.
After some research I figured I might try either typeid(...).hash_code()
however this is not sufficiently constexpr
qualified (Beside the danger of hash collision).
Questions
Is there a better way than building an excessive if ... else ...
labyrinth to handle objects based on their typeid?
Is there a reason why hash_code
is not a const_expr
? Is this a result of the separate compilation of object files?
What is the use of std::type_index
? Considering that it only provides some additional operators (<
, <=
, >
, >=
) why was it not possible to integrate its functionality with std::type_info
?
–
–
I have a feeling you are looking for boost variant and static visitations.
Since variants weren't mentioned, this might be worth posting as an answer. Demonstruction:
Live On Coliru
#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);
Prints
It's a <NIL>
It's a long
It's a C string (ew!)
It's a double
–
–
–
Here is an implementation of something similar to static visitation on boost::any
, using 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;
(Demo)
The idea is that you pass a boost::any
or boost::any const
as the first argument to any_call
, and after that you pass multiple lambdas. The first lambda whose parameter type matches the type of object contained in boost::any
will be called, and then any_call
will return true. If no lambda matches, any_call
will return false.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.