Проблема с порядком оценки в расширении пакета параметров

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

Другие вопросы по тегам