【问题标题】:Using std::apply with variadic packs将 std::apply 与可变参数包一起使用
【发布时间】:2019-02-11 13:21:34
【问题描述】:

我正在尝试创建一个通用类,它采用一组类型,将它们存储在一个元组中,并且可以对它们应用一个函数。

到目前为止,我尝试了以下内容:

#include <tuple>
struct Base{
    virtual void base_function() = 0;
};

template<typename ...T>
struct A : public Base{
    std::tuple<T...> as;
    A(T... pack):as(pack...){};
    void base_function(){
        std::apply([](auto t){t.base_function();}, as);
    }
};

struct B : public Base{
    void base_function(){};
};


struct C : public Base{
    void base_function(){};
};

struct D : A<B, C>{
    D():A(B(),C()){};
};

当在 D 上调用 base_function 时,我希望 apply 在 B 类和 C 类的 base_function 上被调用。但是编译器会生成以下错误:

错误:没有匹配的调用函数
'__invoke(A<T>::base_function() [with T = {B, C}]::<lambda(auto:1)>, std::__tuple_element_t<0, std::tuple<B, C> >&, std::__tuple_element_t<1, std::tuple<B, C> >&)'

【问题讨论】:

  • 您知道,BaseD 类(以及从 Base 继承的任何类)对于最小示例来说不是必需的。即使没有它们,您的问题也会以同样的方式表现出来(@Jarod42 的解决方案也是如此)。
  • @Spencer 删除 D 类不会产生错误,因为编译器不会在没有声明 A 版本的情况下生成任何代码。基类在精简代码时就在那里,并在那里提供一些上下文
  • 但是您可以在声明 D 对象的任何位置声明 A&lt;B,C&gt;

标签: c++ templates c++17 stdapply


【解决方案1】:

std::apply 的第一个参数应该是一个与元组的元素数量相同的函子,所以在你的情况下是可变的:

template <typename ...Ts>
struct A : public Base{
    std::tuple<Ts...> as;
    A(Ts... pack) : as(pack...){}

    void base_function(){
        std::apply([](auto&... ts){(ts.base_function(), ...);}, as);
    }
};

【讨论】:

  • 从未见过 lambda 中使用的语法,您能否解释一下它实际上在做什么。编译器怎么知道对参数包ts做什么?
  • 这很好,但您可能需要解释一下为什么 std::apply 不像 OP 认为的那样工作。
【解决方案2】:

std::apply 没有按照你的想法做。它用于将参数元组传递给函数(可调用类型)。换句话说,元组本身没有名为base_function 的函数。见https://en.cppreference.com/w/cpp/utility/apply

【讨论】:

  • 我将 OP 的困惑解释为认为 apply 采用一元函数并将其依次应用于元组中的每个元素,而不是将一元函数直接应用于元组(这将毫无意义,因为你可以......已经这样做了)。
猜你喜欢
  • 2023-04-07
  • 2014-08-30
  • 2017-10-25
  • 1970-01-01
  • 2014-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
相关资源
最近更新 更多