5

I want to write a function magic_get, which can extract a value from a parameter pack by index, for example:

int n = 0;
n = magic_get<0>(1, 3, 5, 7);
assert(1 == n);
n = magic_get<1>(1, 3, 5, 7);
assert(3 == n);
n = magic_get<2>(1, 3, 5, 7);
assert(5 == n);
n = magic_get<3>(1, 3, 5, 7);
assert(7 == n);

How to implement magic_get?

Constructor
  • 7,273
  • 2
  • 24
  • 66
xmllmx
  • 39,765
  • 26
  • 162
  • 323

1 Answers1

15
template <size_t N, typename... Args>
decltype(auto) magic_get(Args&&... as) noexcept {
    return std::get<N>(std::forward_as_tuple(std::forward<Args>(as)...));
}

Change decltype(auto) to auto and add a trailing return type of decltype(/* the whole returned expression here */) if C++14 features are unavailable.


Tupleless version:

template <std::size_t N, typename Tfirst, typename... Args, std::enable_if_t<N == 0, int>...>
decltype(auto) magic_get(Tfirst&& first, Args&&... as) noexcept {
    return std::forward<Tfirst>(first);
}

template <std::size_t N, typename Tfirst, typename... Args, std::enable_if_t<N != 0, int>...>
decltype(auto) magic_get(Tfirst&& first, Args&&... as) noexcept {
    return magic_get<N - 1>(std::forward<Args>(as)...);
}

Note that this does not work in clang, thanks to clang bug 11723. Replacing std::enable_if_t<N != 0, int>... with std::enable_if_t<N != 0, int> = 0 is a simple workaround.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Is it possible to avoid constructing a tuple object? – xmllmx Jul 12 '14 at 09:35
  • 3
    @xmllmx Yes, it's possible, but why reinvent the wheel? The optimizer will optimize everything out since the tuple is a tuple of references and so its destructor is trivial. – T.C. Jul 12 '14 at 14:13