Расширение пакета параметров C ++ 17 с оценкой параметров функции - PullRequest
3 голосов
/ 07 августа 2020

Я играю с вариативными c шаблонами и выражениями свертки, в частности, делаю преобразования типов для помещения в параметры функций. Я понимаю, что сделать что-то вроде:

template<T, typename ... Args>
void convertAndEvaluate(const vector<T>& convertibles)
{
    size_t i = 0;
    evaluate(some_function<Args>(convertibles[i++])...);
}

не сработает, поскольку порядок оценки входных данных функции не указан. Выражения свертки могут давать правильный порядок оценки, однако их результат заключен в круглые скобки и не может использоваться в качестве входных данных функции. Я могу добиться того же результата с index_sequences с помощью другой шаблонной функции, но мне было интересно, есть ли более лаконичный способ с C ++ 17, что-то вроде использования constexpr с расширением пакета.

Пример игрушки:

#include <iostream>
#include <vector>
#include <utility>

using namespace std;

template<typename ... Args>
class Foo {
public:
    Foo() {}
    
    void just_print(const std::vector<int>& convertible)
    {
        size_t i = 0;
        ((cout << static_cast<Args>(convertible[i++]) << " "), ...);
        cout << endl;
    }

    template<typename T,T... ints>
    void expandEvaluate(const std::vector<int>& values, std::integer_sequence<T, ints...> int_seq)
    {
        eval(static_cast<Args>(values[ints])...);
    }
  
    void convert(const std::vector<int>& convertible)
    {
        expandEvaluate(convertible, std::make_index_sequence<sizeof...(Args)>());
    }
    
    void convert_wrong(const std::vector<int>& convertible)
    {
        size_t i = 0;
        eval(static_cast<Args>(convertible[i++])...);
    }
    
    void eval(const Args&... values)
    {
        ((cout << values << " "), ...);
        cout << endl;
    }
    
};


int main()
{
    
    Foo<double, int, float, int, double> bar;
    bar.eval(3, 4, 5, 6, 7);
    bar.just_print({3, 4, 5, 6, 7});
    bar.convert_wrong({3, 4, 5, 6, 7});
    bar.convert({3, 4, 5, 6, 7});
    return 0;
}

Вывод:

3 4 5 6 7                                                                                                                                                 
3 4 5 6 7                                                                                                                                                 
7 6 5 4 3                                                                                                                                                 
3 4 5 6 7

Edit: ретроспективно, мое решение с целочисленным расширением требует одновременного расширения двух пакетов параметров, это определено в стандарте?

1 Ответ

2 голосов
/ 07 августа 2020

Думаю, ваше решение (использование std::make_index_sequence / std::index_sequence для получения индексов в правильном порядке) является хорошим (и работает также с C ++ 14).

Начиная с C ++ 17 вы также можете использовать std::tuple / std::apply()

void convert2 (std::vector<int> const & cv)
 {
   std::size_t  i{};

   std::tuple  t{ static_cast<Args>(cv[i++])... };
   std::apply([=](auto ... args){ eval(args...); }, t);
 }

, но это почти ваше решение std::make_index_sequence / std::index_sequence, заключенное в std::apply().

...