Search code examples
c++tuplestemplate-meta-programmingboost-fusion

tuple - get_or helper function


I need a tuple helper function that if a requested type does not exist in the tuple it returns a default constructed null type.

e.g.

std::tuple<bool, int> tuple(true, 0);

static_assert(std::is_same<decltype(get_or<double, std::nullptr_t>(tuple)), 
                           std::nullptr_t>::value, "");
assert(get_or<double, std::nullptr_t>(tuple) == nullptr);

I guess I need some boost fusion magic but I haven't quite figured it out. Any suggestions?


Solution

  • Here is a tuple_index helper I have lying around, which returns the index of a given type in a std::tuple. (It can easily be adjusted to work with a predicate such as is_convertible.)

    template< typename elem, typename tup, std::size_t offset = 0 >
    struct tuple_index
        : std::integral_constant< std::size_t, offset > {};
    
    template< typename elem, typename head, typename ... tail, std::size_t offset >
    struct tuple_index< elem, std::tuple< head, tail ... >, offset >
        : std::integral_constant< std::size_t, tuple_index< elem, std::tuple< tail ... >, offset + 1 >::value > {};
    
    template< typename elem, typename ... tail, std::size_t offset >
    struct tuple_index< elem, std::tuple< elem, tail ... >, offset >
        : std::integral_constant< std::size_t, offset > {};
    

    You could build on it like this:

    template< typename result, typename fallback, typename tuple >
    typename std::enable_if< tuple_index< result, typename std::decay< tuple >::type >::value
                             == std::tuple_size< typename std::decay< tuple >::type >::value,
        fallback >::type
    get_or( tuple && t ) { return {}; }
    
    template< typename result, typename fallback, typename tuple >
    typename std::enable_if< tuple_index< result, typename std::decay< tuple >::type >::value
                             != std::tuple_size< typename std::decay< tuple >::type >::value,
        result >::type
    get_or( tuple && t ) {
        return std::get< tuple_index< result, typename std::decay< tuple >::type >::value >
            ( std::forward< tuple >( t ) );
    }
    

    http://ideone.com/ZdoWI7

    All the decay is necessary because the metafunctions discriminate between tuple and tuple &.