参数包扩展中的评估顺序问题
Problem with order of evaluation in parameter pack expansion
我写了一个模板,它接受一个 istream&
和一个函数,应该从 istream
中提取这个函数的所有参数,用这些参数和 return 调用函数结果。一切正常,除了函数参数的评估顺序。请参阅下面的代码、更多详细信息和最后一个问题:
#include <iostream>
#include <vector>
void Foo(int i, std::string s)
{
std::cout << "input was " << i << " and " << s << '\n';
}
template<typename T>
T Parse(std::istream &s)
{
T res;
s >> res;
return res;
}
template<typename TR, typename ... TArgs>
TR Bar(std::istream &s, TR f(TArgs...) )
{
return f(Parse<TArgs>(s)...);
}
int main()
{
Bar(std::cin, Foo);
}
输入:
1 2
预期输出:
input was 1 and 2
实际输出:
input was 2 and 1
我知道函数参数的评估是特定于实现的,显然这里最后一个参数首先被评估并读取第一个输入。
如何修复此代码并强制对参数执行特定的求值顺序?也许在调用函数之前分别评估它们?是否有可能在不违反标准的情况下 and/or 依赖于特定的实现或编译器?
例如,我们可以使用一个中间值std::tuple
来强制求值顺序:
template<typename TR, typename ... TArgs>
TR Bar(std::istream &s, TR f(TArgs...) )
{
std::tuple<TArgs...> args{Parse<TArgs>(s)...};
return std::apply(f, std::move(args));
}
与函数参数相反,花括号列表中参数的求值顺序由它们在该列表中的顺序固定,[dcl.init.list/4]:
Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions, are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list. [ Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. ]
我写了一个模板,它接受一个 istream&
和一个函数,应该从 istream
中提取这个函数的所有参数,用这些参数和 return 调用函数结果。一切正常,除了函数参数的评估顺序。请参阅下面的代码、更多详细信息和最后一个问题:
#include <iostream>
#include <vector>
void Foo(int i, std::string s)
{
std::cout << "input was " << i << " and " << s << '\n';
}
template<typename T>
T Parse(std::istream &s)
{
T res;
s >> res;
return res;
}
template<typename TR, typename ... TArgs>
TR Bar(std::istream &s, TR f(TArgs...) )
{
return f(Parse<TArgs>(s)...);
}
int main()
{
Bar(std::cin, Foo);
}
输入:
1 2
预期输出:
input was 1 and 2
实际输出:
input was 2 and 1
我知道函数参数的评估是特定于实现的,显然这里最后一个参数首先被评估并读取第一个输入。
如何修复此代码并强制对参数执行特定的求值顺序?也许在调用函数之前分别评估它们?是否有可能在不违反标准的情况下 and/or 依赖于特定的实现或编译器?
例如,我们可以使用一个中间值std::tuple
来强制求值顺序:
template<typename TR, typename ... TArgs>
TR Bar(std::istream &s, TR f(TArgs...) )
{
std::tuple<TArgs...> args{Parse<TArgs>(s)...};
return std::apply(f, std::move(args));
}
与函数参数相反,花括号列表中参数的求值顺序由它们在该列表中的顺序固定,[dcl.init.list/4]:
Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions, are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list. [ Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. ]