【问题标题】:Variadic template parameter order problem可变模板参数顺序问题
【发布时间】:2019-02-21 18:45:47
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 有什么理由不只是使用std::function
  • 另外,你能用C++17吗?
  • 我的函数包装器使用继承和虚函数。
  • 并非我的库的所有用户都可以使用 C++11 或更高版本。
  • 我添加了 C++11 标签,所以人们会知道它仅限于此。

标签: c++ templates variadic-templates c++03 template-argument-deduction


【解决方案1】:

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

template <typename>
struct myFunc;

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

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

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

如下

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

其中funR(*)(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 struct接收在一个类型(相同的指针类型)之前,然后是该类型的值。

所以

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

【讨论】:

  • 看来 OP 想要 template &lt;typename F, F f&gt; struct myFunc; 或 C++17 template &lt;auto f&gt; struct myFunc;
  • @Jarod42 - 是的...我已经添加了auto C++17 版本...也许我可以添加一个 C++17 之前的示例...
  • @Jarod42 - 好的:现在我提出两种解决方案......但可能会令人困惑:(
  • @max66 这是一个开源模板库,它必须尽可能支持嵌入式应用程序的 C++03。函数指针作为模板参数的目的是为了最大限度地提高中断回调的效率。
猜你喜欢
  • 2011-09-28
  • 1970-01-01
  • 2012-11-05
  • 1970-01-01
  • 2012-02-05
  • 2016-12-01
  • 2013-04-01
  • 1970-01-01
相关资源
最近更新 更多