3

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?

ronag
  • 49,529
  • 25
  • 126
  • 221
  • You first line shouldn't compile. You need to pass a second constructor argument. – juanchopanza Jul 09 '13 at 06:02
  • @juanchopanza - I think that the first line is actually the question. He wants to be able to initialize the tuple like that and have the 2nd argument be set to it's default – asafrob Jul 09 '13 at 06:14
  • @asafrob Ah OK. The way the problem is presented threw me. No helper function will fix that compiler error. – juanchopanza Jul 09 '13 at 06:16
  • I think this is the same question http://stackoverflow.com/questions/13301863/is-it-possible-to-set-the-default-value-of-stdtr1tuple – asafrob Jul 09 '13 at 06:21
  • @juanchopanza: You are right. I've fixed the typo. – ronag Jul 09 '13 at 06:46

1 Answers1

2

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 &.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • Great! Though I was hoping on a simpler a helper function using boost mpl or fusion? – ronag Jul 09 '13 at 08:29
  • This is quite simple already, just verbose due to `decay` which I copy-pasted. You could factor it out by dispatching through an intermediary. Also I sort of doubt `forward` is doing anything; i just added it defensively. – Potatoswatter Jul 09 '13 at 09:52