【问题标题】:Applying vector of arguments of known size to virtual variadic function将已知大小的参数向量应用于虚拟可变参数函数
【发布时间】:2020-01-28 19:30:22
【问题描述】:

在下面的代码示例中,我将通过run() 方法调用具有已初始化参数vect 的具体foo() 函数。对于编译,我使用 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();
}

【问题讨论】:

  • 因为您在编译时就知道vect 中将存储多少元素,您可以使用std:array 代替,这与std::apply 相同。还是施工后需要改尺寸?
  • @1201ProgramAlarm 谢谢你的回复。目前,对于我创建的对象类型,不需要更改它们的大小。但在该项目的未来,我也有兴趣在建设后可能扩大规模。您对此案有何建议?

标签: c++ variadic-templates virtual variadic-functions


【解决方案1】:

使用 C++14 中的 std::index_sequence 有助于处理此类问题:

制作第二个版本的 run,它采用一系列 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

【讨论】:

  • 开箱即用!我也有一些新概念需要学习。
【解决方案2】:

下面我不确定我对std::apply的用法...

我发现您在使用std::apply()时存在两个问题

(1) std::apply() 需要 std::tuple 或类似参数作为第二个参数。对于“或类似”,我的意思是“或std::arraystd::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() 的第一个参数与(非静态)方法不兼容。

但你可以将它的使用包装在 lambda 中,所以我建议

        lastResult = std::apply([=](auto ... args)
                                { return this->foo(args...); },
                                this->vect);

【讨论】:

  • 感谢您解决我的代码不足的问题。接下来,我需要使用 lambdas 来详细了解您的解决方案。
猜你喜欢
  • 2016-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多