添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
发财的青椒  ·  Registered driver ...·  8 月前    · 
文雅的火锅  ·  C# ...·  1 年前    · 
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?
  • hash_code() is not constexpr because type_info may be polymorphic. There was discussion about proposing a way to get a compile-time identifier for a type, but I don't think it went anywhere? – Collin Dauphinee Dec 8, 2014 at 23:58 The technique I'm referring to by "computed goto" is one of the possible ways that switch can be compiled. It uses a jump table, the control variable being what is used to find the entry in the table. The compiler may choose to compile a switch statement using a series of conditionals (exactly like if/else) if the generated jump table wouldn't be sufficiently dense. (Further reading) – cdhowie Dec 9, 2014 at 16:17

    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
                    Where is the advantage of boost::varaint over  boost::any? What would be the best way to mark null values? (adding void* to the template parameters?)
    – ted
                    Dec 9, 2014 at 12:39
                    @ted Why void*? It's not C anymore :) struct Nil {}; boost::variant<Nil, double, long, blob_t...> and you're on your way. Updated the sample Live On Coliru
    – sehe
                    Dec 9, 2014 at 14:05
                    Oh, re Where is the advantage: the advantage is that you leave the type discrimination to Boost Variant and never leave type safety, nor deal with potential hairiness surrounding typeid.
    – sehe
                    Dec 9, 2014 at 14:07
    

    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.