问题描述
我编写了一个模板,该模板带有一个istream
和一个函数,应该从#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
实际输出:
AuthService
我知道功能参数的评估是特定于实现的,显然,这里最后一个参数首先被评估并读取第一个输入。
如何解决此代码并在参数上强制执行特定的求值顺序?也许在调用函数之前分别评估它们?甚至有可能在不违反标准和/或不依赖特定实现或编译器的情况下进行
?解决方法
例如,我们可以使用中间的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]中的顺序确定:
在括号初始化列表的初始化器列表中,初始化器子句,包括由于包扩展而产生的所有子句,按照它们出现的顺序进行评估。就是说,与给定的 initializer-clause 相关的每个值计算和副作用都在其后的与任何 initializer-clause 相关的每个值计算和副作用之前进行排序。 initializer-list 的逗号分隔列表。 [注:无论初始化的语义如何,此评估顺序均成立;例如,它通常适用于将 initializer-list 的元素解释为构造函数调用的参数的情况,即使通常对该调用的参数没有排序约束。 ]