C ++中的模板特化和函数重载

时间:2015-06-26 18:13:04

标签: c++ templates c++11 polymorphism overloading

我正在尝试构建一个静态包装函数,它可以调用成员和非成员函数指针。

我想出的是如下 -

template <typename Derived>
struct CallAny {
  template<typename F> using ReturnType = typename std::function<typename std::remove_pointer<F>::type>::result_type;

  template<typename F, bool IsMember, typename... Args>
  static ReturnType<F> function_wrapper(Derived* obj, F func, Args... args);

  template<typename F, typename... Args>
  static ReturnType<F> function_wrapper<F, true, Args...>(Derived *obj, F func, Args... args) {
    return obj->*func(args...);
  }

  template<typename F, typename... Args>
  static ReturnType<F> function_wrapper<F, false, Args...>(Derived *obj, F func, Args... args) {
    return func(args...);
  }

};

struct CallAnyDerived : public CallAny<CallAnyDerived> {}; 

这里F是一个函数指针类型,必须使用Args...中给出的参数调用。 F可能是C风格的函数指针或继承自Derived的类CallAny的成员。

当我尝试编译此代码时,我收到错误消息 -

XXXXXXXXXXX: error: function template partial specialization ‘fucntion_wrapper<F, true, Args ...>’ is not allowed
   static ReturnType<F> function_wrapper<F, true, Args...>(Derived *obj, F func, Args... args) {
                                                                                             ^
XXXXXXXXXXX: error: function template partial specialization ‘fucntion_wrapper<F, false, Args ...>’ is not allowed
   static ReturnType<F> function_wrapper<F, false, Args...>(Derived *obj, F func, Args... args) {
                                                                                              ^

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:4)

通常,您不能部分专门化功能。解决这个问题的方法是创建一个类似static R call(...)之类的辅助结构,并部分地专门化辅助结构。

在这种情况下,您根本不需要模板专业化,您可以使用重载

template <typename Derived>
struct CallAny {
  template<typename F> using ReturnType = typename std::function<typename std::remove_pointer<F>::type>::result_type;

  // takes pointer to member function
  template<typename R, typename... Ts, typename... Args>
  static R function_wrapper(Derived* obj, R (Derived::*func)(Ts...), Args... args) {
    return obj->*func(args...);
  }

  // takes everything else
  template<typename F, typename... Args>
  static ReturnType<F> function_wrapper(Derived *obj, F func, Args... args) {
    return func(args...);
  }

};

答案 1 :(得分:1)

您可以使用SFINAE:

template <typename Derived>
struct CallAny {
  template<typename F, typename... Args>
  static
  auto
  function_wrapper(Derived* obj, F func, Args&&... args)
  -> std::enable_if_t<
         std::is_member_function_pointer<F>::value,
         decltype((obj->func)(std::forward<Args>(args)...))>
  {
      return (obj->func)(std::forward<Args>(args)...);
  }

  template<typename F, typename... Args>
  static
  auto
  function_wrapper(Derived* obj, F func, Args&&... args)
  -> std::enable_if_t<
         !std::is_member_function_pointer<F>::value,
         decltype(func)(/*obj,*/std::forward<Args>(args)...))>
  {
      return func(/*obj,*/std::forward<Args>(args)...);
  }

};

或标签调度:

template <typename Derived>
struct CallAny {
  template<typename F, typename... Args>
  static
  auto
  function_wrapper(Derived* obj, F func, Args&&... args)
  {
      return impl(std::is_member_function_pointer<F>{}, obj, func, std::forward<Args>(args)...);
  }

  template<typename F, typename... Args>
  static
  auto
  impl(std::true_type, Derived* obj, F func, Args&&... args)
  -> decltype((obj->func)(std::forward<Args>(args)...))
  {
      return (obj->func)(std::forward<Args>(args)...);
  }

  template<typename F, typename... Args>
  static
  auto
  impl(std::true_type, Derived* obj, F func, Args&&... args)
  -> decltype(func)(/*obj,*/std::forward<Args>(args)...))>
  {
      return func(/*obj,*/std::forward<Args>(args)...);
  }
};