Применение вектора аргументов известного размера к виртуальной функции variadi c - PullRequest
1 голос
/ 28 января 2020

в следующем примере кода я собираюсь вызвать конкретную foo() функцию с уже инициализированными аргументами vect через run() метод. Для компиляции я использую VS19 с C ++ 17. В следующем я не уверен в моем использовании std::apply ... Любая помощь приветствуется;)

#include <iostream>
#include <vector>
#include <tuple>
using namespace std;

template<typename ...T>
struct Base {
    vector<int> vect;
    Base(){
        static const std::size_t size = sizeof...(T);

        for (int i = 0; i < size; i++)
            vect.push_back((i+1)*(i+1)); //some initialization
    }
};

template<typename ...T>
struct Derived : public Base<T...> {
    virtual int foo(T...) = 0;

    int lastResult;

    void run() {
        if (this->vect.size() > 0) {
            lastResult = std::apply(foo, this->vect);
        }else{
            lastResult = -1;
            cout << "0 arguments case" << endl;
        } 
    }

};


struct D0 : public Derived<> {
    int foo() override { return 0; } 
};

struct D1 : public Derived<int> {
    int foo(int a) override { return a * a; } 
};

struct D2 : public Derived<int,int> {
    int foo(int a, int b) override { return a + b; }
};


int main() {
    D0 d0;
    cout << d0.foo() << endl; // 0
    //d0.run(); //vect = {}, lastResult = -1, "0 arguments case"

    D1 d1;
    cout << d1.foo(1) << endl; // 1
    //d1.run(); //vect = {1} -> lastResult = 1

    D2 d2;
    cout << d2.foo(1, 2) << endl; // 3
    //d2.run(); //vect = {1,4} -> lastResult = 5


    cin.get();
}

Ответы [ 2 ]

0 голосов
/ 28 января 2020

В следующем я не уверен относительно моего использования std::apply ...

Я вижу две проблемы в вашем использовании std::apply()

( 1) std::apply() требует std::tuple или аналогичный для второго аргумента. Для "или подобного" я имею в виду "или std::array или std::pair".

Так что ваш std::vector не работает.

Полагаю, вы можете использовать std::array.

Я предлагаю следующее Base

template<typename ...T>
struct Base {
   std::array<int, sizeof...(T)> vect;

   template <int ... Is>
   Base (std::integer_sequence<int, Is...>) : vect {{ (Is+1)*(Is+1) ... }}
    { }

   Base () : Base{std::make_integer_sequence<int, sizeof...(T)>{}}
    { }
};

(2) первый аргумент std::apply() не совместим с (не stati c) методом.

Но вы можете обернуть это использование в лямбду, поэтому я предлагаю

        lastResult = std::apply([=](auto ... args)
                                { return this->foo(args...); },
                                this->vect);
0 голосов
/ 28 января 2020

Использование std::index_sequence из C ++ 14 помогает с такими вещами:

Создайте вторую версию прогона, которая принимает последовательность size_t аргументов шаблона, и используйте std::index_sequence_for для их заполнения. :

template <size_t... Is>
void runImpl(std::index_sequence<Is...>) { ... }

void run() { return runImpl(std::index_sequence_for<T...>{}); }

Затем в runImpl можно расширить целые числа шаблона для передачи значений вектора в качестве параметров функции:

if (this->vect.size() > 0) {
    lastResult = foo(Base<T...>::vect[Is]...);
}else{
    lastResult = -1;
    cout << "0 arguments case" << endl;
} 

Демонстрация: https://godbolt.org/z/ZGroAH

...