Проблема с порядком оценки в расширении пакета параметров
Я написал шаблон, который требует
istream&
и функцию, и предполагается, что все параметры этой функции извлекаются из
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
Я знаю, что оценка параметров функции зависит от реализации, и, очевидно, здесь сначала оценивается последний параметр и считывается первый ввод.
Как мне исправить этот код и установить определенный порядок оценки параметров? Может быть, оценить их по отдельности перед вызовом функции? Возможно ли это без нарушения стандарта и / или использования конкретной реализации или компилятора?
1 ответ
Например, мы можем использовать промежуточный
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]:
В инициализаторах-лист в виде рамно-INIT-листа, то инициализатор-положение, включая любые, возникающий в результате разложения пакета, оценивается в том порядке, в котором они появляются. То есть каждое вычисление значения и побочный эффект, связанный с данным предложением инициализатора, упорядочивается перед каждым вычислением значения и побочным эффектом, связанным с любым предложением инициализатора, которое следует за ним в списке, разделенном запятыми, в списке инициализаторов. [Примечание: этот порядок оценки сохраняется независимо от семантики инициализации; например, это применяется, когда элементы списка инициализаторов интерпретируются как аргументы вызова конструктора, даже если обычно нет ограничений последовательности для аргументов вызова. ]