类型:仅推断可变参数模板的参数类型

type deducing only the arguments types for a variadic template

提问人:Patrick Fromberg 提问时间:10/25/2023 最后编辑:Patrick Fromberg 更新时间:10/25/2023 访问量:58

问:

我正在尝试将可变参数模板函数应用于元组。我找到了以下适用于 C++14 的解决方案(参见 https://stackoverflow.com/a/37100646/2712726)。

#include <tuple>
template <typename T, typename U> void my_func(T &&t, U &&u) {}
int main(int argc, char *argv[argc]) {
  std::tuple<int, float> my_tuple;
  std::apply([](auto &&... args) { my_func(args...); }, my_tuple);
  return 0;
}

我还发现了许多针对 C++11 的解决方案,但没有编译的解决方案。所以我实现了自己的解决方案,它也无法编译。

以下代码显示了我的尝试。我的问题是为什么最后一条语句中的类型推导失败,以及我是否可以以某种方式帮助编译器。u.apply(f)

#include <iostream>
#include <tuple>

using namespace std;

template <typename... T>
struct parameter_pack : public parameter_pack<T>... {
    parameter_pack(const T&... t) : parameter_pack<T>(t)... {}

    // C++11
    template <template <typename...> class Func>
    void apply(Func<T...> f) {
        f(parameter_pack<T>::h...);
    }
    //c++14 works
    // template <typename Func>
    // void apply(Func f) {
    //     f(parameter_pack<T>::h...);
    // }

    // UPDATE:
    // This solution from Holy Black Cat Works great with C++11 too
    //void apply(void (*f)(const T&...)) {
    //    f(parameter_pack<T>::h...);
    //}
};

template <typename H>
struct parameter_pack<H> {
    parameter_pack(const H& h) : h(h) {}
    const H& h;
};

template <typename... T>
parameter_pack<T...> make_parameter_pack(const T&... t) {
    return parameter_pack<T...>(t...);
}

// test function f()
template <typename H>
void f(const H& h) {
    std::cout << h << std::endl;
}

template <typename H, typename... T>
void f(const H& h, const T&... t) {
    f(h);
    f(t...);
}

int main() {
    auto u = make_parameter_pack(1, 1.1, "hello");
    std::cout << std::endl;
    // C++11
    u.apply(f); // compiler error

    //C++14 works
    // auto lambda = [&](const auto&... args) {
    //    f(args...);
    // };
    // u.apply(lambda);
}

编译器说:

<source>:49:7: error: no matching member function for call to 'apply'
   49 |     u.apply(f);
      |     ~~^~~~~
<source>:12:10: note: candidate template ignored: couldn't infer template argument 'Func'
   12 |     void apply(Func<T...> f) {
      |          ^
1 error generated.
Compiler returned: 1

更新我添加了 Holy Cat 的解决方案并在代码中标记为 UPDATE。那行得通。

C++ C++11 应用 可变模板 类型演绎

评论

0赞 HolyBlackCat 10/25/2023
1. 是 C++17,而不是 C++14。2. 你为什么要重新发明,而不仅仅是写你自己的替代品?您的版本不适用于单元素包,也不适用于具有非唯一类型的包。std::applystd::tuplestd::applystd::tuple
0赞 HolyBlackCat 10/25/2023
Func<T...> f不起作用,因为 or of 的类型不是某些模板的专用化,它只是 .唯一合理的选择是使函数成为结构的成员,并传递整个结构(模仿 C++14 泛型 lambda 正在做的事情)。ff<....>void(/*something*/)
0赞 Patrick Fromberg 10/25/2023
实现我自己的还不够好,因为它不能应用带有可变参数模板参数的函数,因此自 C++14 以来才需要它。std::apply[](auto&&...args){...}
0赞 HolyBlackCat 10/25/2023
这并不能解释重新实现,无论您最终得到什么解决方案都可以接受。直接接受可变参数函数是不可行的(我认为这是可能的,但你需要知道确切的类型,这意味着没有参数的隐式转换,必须提前知道返回类型等)。最好接受函子类。std::tuplestd::tuple
1赞 HolyBlackCat 10/25/2023
您的意思可能是 ,它按原样适用于您的代码,但如果函数(例如按值接受参数)或返回 void 以外的内容,则很快就会中断。这就是为什么我说这是不可行的。void apply(void (*f)(const T &...)) {f(parameter_pack<T>::h...);}

答:

3赞 Vivick 10/25/2023 #1

f是一个函数模板,你不能取“函数蓝图”的地址。比方说,您可以取 的地址,但不能取 的地址。f<int>f

为什么它适用于 lambda?因为 lambda 只是可调用结构的语法糖:您将传递一个存在于内存中某个位置的对象,因此调用运算符是模板这一事实没有影响。如果你通过了或任何变体,你会回到与上面相同的问题。lambda::operator()