std::apply是否保证评估的顺序?

3
在C++中,函数调用的参数表达式的求值顺序是未指定的。当我使用std::apply时,是否有保证函数按照元组的元素顺序被调用?我有一个需要按照顺序先对元组的第一个元素应用函数,然后是第二个,第三个......的情况。
作为反例:
template <class Tuple, size_t... Is>
void function(Tuple t, std::index_sequence<Is...>) {
    some_func( my_func(get<Is>(t))... );
}

不保证my_func在元组的每个元素上被调用的顺序。


1
你是什么意思,所谓“按顺序调用”?它不是为每个元组元素单独调用;它只被调用一次,并将元组元素作为参数。 - user2357112
@BenVoigt:我觉得提问者期望std::apply(f, std::make_tuple(1, 2))调用f(1)f(2),而不是f(1, 2) - user2357112
@user2357112:我猜John打算使用大括号初始化列表,其中评估的顺序是有保证的,来调用'my_func',然后需要使用'std::apply'将该大括号初始化列表作为'some_func'的许多参数传递。 - Ben Voigt
约翰,对于 my_func 的所有输入类型,返回类型是否相同? - Ben Voigt
不,我的意思是在元组中的不同类型上调用重载函数。重载函数返回与参数相同的类型。 - John
2个回答

5
我认为这应该没问题:
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))... });

因为所有的my_func调用都在一个大括号初始化列表内,所以它们会按顺序被计算。虽然std::apply对于some_func的调用是必需的,但是排序保证并不来自于std::apply
需要注意的是,由于元组不是聚合体,因此它是通过构造函数调用进行构造的,构造函数参数通常不按顺序计算。然而,使用大括号仍然可以保证顺序,详见:

一个对我的问题有不同理解的好答案。尽管目前接受标记的位置,我不确定谁的解释更准确。 - user2357112
我认为Ben给了我我正在寻找的答案!我想我需要一段时间来消化它。 - John

4

我有这样一个情况,函数首先应用于元组的第一个元素,然后是第二个,第三个......顺序很重要。

那么你使用了错误的函数,因为std::apply与你想要的完全无关。例如:

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

返回值

f(1, 2)

与其尝试单独调用 f(1)f(2)


那么对于一些适当的 Tstd::apply(some_func, T { my_func(get<Is>(t))... }) 又怎么样呢? - Ben Voigt
我认为 user2357112 是正确的。std::apply 不是我想要的工具。 - John

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接