2314. apply() should return decltype(auto) and use decay_t before tuple_size

Section: 23.3.1 [intseq.general] Status: C++14 Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2017-07-06

Priority: 0

View all issues with C++14 status.

Discussion:

The example in 23.3.1 [intseq.general]/2 depicts apply_impl() and apply() as returning auto. This is incorrect because it will trigger decay and will not preserve F's return type. For example, if invoking the functor returns const int&, apply_impl() and apply() will return int. decltype(auto) should be used for "perfect returning".

Additionally, this depicts apply() as taking Tuple&&, then saying "std::tuple_size<Tuple>::value". This is incorrect because when apply() is called with lvalue tuples, perfect forwarding will deduce Tuple to be cv tuple&, but 23.5.3.6 [tuple.helper] says that tuple_size handles only cv tuple, not references to tuples. Using remove_reference_t would avoid this problem, but so would decay_t, which has a significantly shorter name. (The additional transformations that decay_t does are neither beneficial nor harmful here.)

[Issaquah 2014-02-11: Move to Immediate]

Proposed resolution:

This wording is relative to N3691.

  1. Edit the example code in 23.3.1 [intseq.general]/2 as indicated:

    template<class F, class Tuple, std::size_t... I>
      autodecltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence<I...>) {
        return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
      }
    template<class F, class Tuple>
      autodecltype(auto) apply(F&& f, Tuple&& t) {
        using Indices = make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
        return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices());
      }