可变模板专业化问题

时间:2017-01-24 14:43:23

标签: c++ c++11 templates variadic-templates

我想要一种通用的方法来处理函数并最终调用它们所以我编写下面的代码问题就是代码正在编译但是当我测试它时我得到了类似的错误

  

模板参数数量错误(1,应为0)      auto al = action :: apply< 5> :: value;

所以我知道我做错了什么但我无法弄清楚它是什么。

template<typename T, typename enabled=void, typename ...P>
struct action{
    template<P... args>
    struct apply{ };
};

template<typename FN,typename ...P>
struct action<FN, typename std::enable_if< std::is_function<FN>::value >::type ,P...>{
    template<P... args>
    struct apply{ 
         static const  decltype( std::result_of<FN(P...)>::type ) value = FN( std::forward<P>(args)...);
    };
};


int test(int x)
{
    return x;
}

int main()
{
  auto al= action<decltype(test), int>::apply<5>::value;
  std::cout << "result :" << al <<std::endl;
  return 0;
}

1 个答案:

答案 0 :(得分:8)

这是您的主要模板:

template<typename T, typename enabled=void, typename ...P>
struct action

无论何时执行action<blah>,都会通过此主模板解释参数。

action<decltype(test), int>

所以在这里,您将decltype(test)传递为T,将int传递为enabled。没有...P

然后我们测试是否适用任何模板专业化。

template<typename FN,typename ...P>
struct action<FN, typename std::enable_if< std::is_function<FN>::value >::type ,P...>

这需要分解。 action之后的部分是我们模式匹配的部分。 之前的部分只是我们从中推导出的一些变量。

所以

action<decltype(test), int>
struct action<FN, typename std::enable_if< std::is_function<FN>::value >::type ,P...>

排队:

       action<decltype(test), int>
struct action<FN            , typename std::enable_if< std::is_function<FN>::value >::type ,P...>

以下是它们的对应方式:

FN=decltype(test)
typename std::enable_if< std::is_function<FN>::value >::type=int
P...=

好的,所以参数1是decltype(test),又名int(int)。我们将其推导为FN。一切都好。

接下来,有两个参数。所以...P显然是空的。

参数2处于非推导的上下文中。我们会计算出来的:

typename std::enable_if< std::is_function<FN>::value >::type
typename std::enable_if< std::is_function<int(int)>::value >::type
typename std::enable_if< true >::type
void

......好吧,这个专业化说它是void。但我们通过了int。由于void=int是无意义的,因此此专业化不适用。我们在这里没有模式匹配。

因此我们回到主要专业化:

template<typename T, typename enabled=void, typename ...P>
struct action{
  template<P... args>
  struct apply{ };
};

好的,所以它有一个成员模板apply,只有0个非类型参数,因为...P是空的。

因此你的错误。

专业化不是重载。它们是主模板的模式匹配实现替换。主模板参数始终是签名。专业化可以重命名和模式匹配某些选择。

您可能想要使用别名。将action重命名为action_helper。 (可选)将其放在details命名空间中。然后:

template<class T, class...P>
using action = action_helper<T,void,P...>;

并在客户端代码中使用action