3

In c++, the order of evaluation of expressions provided as parameters for a function call is not specified. When I use std::apply is there a guarantee that the function is called IN ORDER on the elements of the tuple? I have a case where it matters that the function is first applied to the first element of the tuple, then the second, then the third, ....

As a counter example:

template <class Tuple, size_t... Is>
void function(Tuple t, std::index_sequence<Is...>) {
    some_func( my_func(get<Is>(t))... );
}

will not guarantee the order that my_func is called on each element of the tuple.

John
  • 2,326
  • 1
  • 19
  • 25
  • 1
    What do you mean, "called in order"? It's not called separately for each tuple element; it's called *once*, with the tuple elements as arguments. – user2357112 May 14 '17 at 00:42
  • @BenVoigt: It sounds to me like the questioner is expecting `std::apply(f, std::make_tuple(1, 2))` to call `f(1)` and `f(2)`, rather than `f(1, 2)`. – user2357112 May 14 '17 at 00:51
  • @user2357112: I presume John is intending to use a braced-initializer-list, where the order of evaluation *is* guaranteed, to call `my_func`, and then needs `std::apply` to get that braced-initializer-list passed as the many arguments of `some_func`. – Ben Voigt May 14 '17 at 00:52
  • John, is the return type of `my_func` the same for all input types? – Ben Voigt May 14 '17 at 00:53
  • No. I mean to call an overloaded function on the different types in the tule. The overloaded function returns the same type as the argument. – John May 14 '17 at 12:54

2 Answers2

5

I think this should work:

using args_tuple_type = decltype( std::make_tuple(my_func(get<Is>(t))...) );
std::apply(some_func, args_tuple_type{ my_func(get<Is>(t))... });

Because the my_func calls are all inside a braced-initializer-list, they are evaluated in sequence. std::apply is needed for the some_func call, but the ordering guarantee doesn't come from std::apply.

Not that because the tuple is not an aggregate, it is constructed via a constructor call, and constructor function arguments aren't normally evaluated in order. However, use of the braces still grants the ordering, as explained at

Community
  • 1
  • 1
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • A good answer to a different reading of the question from mine. Despite the current placement of the accept checkmark, I'm not sure whose interpretation is more accurate. – user2357112 May 14 '17 at 01:00
  • I think Ben has given me the answer I was looking for! I think I'll have to digest it awhile. – John May 14 '17 at 01:09
4

I have a case where it matters that the function is first applied to the first element of the tuple, then the second, then the third, ....

Then you're using the wrong function, because std::apply does something completely unrelated to what you want. For example,

std::apply(f, std::make_tuple(1, 2))

returns

f(1, 2)

rather than trying to call f(1) and f(2) separately.

user2357112
  • 260,549
  • 28
  • 431
  • 505