首页 > 解决方案 > 可变模板参数顺序问题

问题描述

我有一个模板化的函数包装器,我正在尝试将其更新为 C++11 语法(可变参数)。

我的问题是我陷入了“catch 22”,其中 ' Args...' 必须是最后一个模板参数,但同时不能在函数指针模板参数之后定义。

知道这是否真的可以解决吗?

  template <typename... Args, void(*Function)(Args...)>
  class function
  {
  public:

    void operator ()(Args... args) const
    {
      (*Function)(std::forward<Args...>(args...));
    }
  };

标签: c++templatesvariadic-templatesc++03template-argument-deduction

解决方案


一种可能的方法是使用模板专业化

template <typename>
struct myFunc;

template <typename R, typename ... Args>
struct myFunc<R(*)(Args...)>
 {
   // ...
 };

但是,这样,您拦截(作为模板参数)函数指针的类型,而不是函数指针本身;所以你必须以某种方式传递函数指针(构造函数?)。

还要注意,如果你想使用完美转发,你必须operator()在模板方法中转换接收参数作为通用引用(&&)。

如下

   template <typename ... As>
   R operator() (As && ... args) const
    {
      return fun(std::forward<As>(args)...);
    }

wherefun是类型的指针R(*)(Args...)

下面是一个完整的编译示例

#include <iostream>
#include <utility>

int foo (int, long)
 { return 42; }

template <typename>
struct myFunc;

template <typename R, typename ... Args>
struct myFunc<R(*)(Args...)>
 {
   using  funPnt = R(*)(Args...);

   funPnt  fun = nullptr;

   myFunc (funPnt f0) : fun{f0}
    { }

   template <typename ... As>
   R operator() (As && ... args) const
    {
      return fun(std::forward<As>(args)...);
    }
 };

int main ()
 { 
   myFunc<decltype(&foo)>  mf0{&foo};

   std::cout << mf0(1, 2l) << std::endl;
 }

如果您真的希望指针函数作为模板参数(但是,这样,每个函数确定不同的类型;这可能是好是坏根据您的需要),您可以myFunc在类型之前编写结构接收(相同指针类型),然后是该类型的值。

所以

template <typename T, T>
struct myFunc;

template <typename R, typename ... Args, R(*Func)(Args...)>
struct myFunc<R(*)(Args...), Func>
 {
   template <typename ... As>
   R operator() (As && ... args) const
    {
      return Func(std::forward<As>(args)...);
    }
 };

可以声明的

 myFunc<decltype(&foo), foo>  mf0;

如果可以使用 C++17,则可以简化auto模板值类型的使用;所以你可以避免类型

template <auto>
struct myFunc;

template <typename R, typename ... Args, R(*Func)(Args...)>
struct myFunc<Func>
 {
   template <typename ... As>
   R operator() (As && ... args) const
    {
      return Func(std::forward<As>(args)...);
    }
 };

myFunc您可以按如下方式创建一个对象

myFunc<&foo> mf0;

附录:如果可以使用C++17,可以为第一个例子定义一个推导指南(指针作为成员,不作为模板值参数)

template <typename R, typename ... Args>
myFunc (R(*)(Args...))  -> myFunc<R(*)(Args...)>;

所以,而不是

myFunc<decltype(&foo)>  mf0{&foo};

你可以简单地写

myFunc  mf0{&foo};

题外话:我希望你知道你在重新发明轮子。正如 NathanOliver 所建议的,该标准提供std::function.


推荐阅读