检查方法的模板特化是否存在

时间:2017-12-11 06:03:58

标签: c++ templates c++14 sfinae

我们说我有一个这样的模板类:

template<typename TRequest, typename TResponse = void>
class handler
{
private:
    static void validate_core(const TRequest& request);
    static TResponse process_core(const TRequest& request);
public:
    static TResponse process(const TRequest& request)
    {
        if (validate_core is implemented)
        {
            log("begin validate");
            validate_core(request);
        }

        return process_core(request);
    }
};

process_core必须针对不同的TRequest / TResponse类型实现,而validate_core是可选的,我想在实现时调用它。

目前,我的解决方法是向validate_core提供默认的空实现,如果它不是专用的,则调用空方法。我想知道是否有更好的方法。

2 个答案:

答案 0 :(得分:0)

如果实现模板专业化,则无法在编译时检查。最好通过声明和外部模板实例化来生成链接时错误。

我理解你希望process实现所谓的模板方法设计模式。如果是这种情况,您可能会发现以下CRTP的使用很有意思。 (Nota bene:我修改了函数签名以使这段代码可编辑)

template<class Derived, typename TRequest, typename TResponse>
class handler_base
{
private:
//caution trickery
static constexpr bool validate_core=false;

public:
static TResponse* process(const TRequest& request)
  {
    if constexpr (Derived::validate_core)
    {
        //log("begin validate");
        Derived::validate_core(request);
    }

    return Derived::process_core(request);
  }
};

template<typename TRequest, typename TResponse=void>
class handler;

class Req1;
class Req2;
class Resp1;
class Resp2;

template<>
class handler<Req1,Resp1>
  : handler_base<handler<Req1,Resp1>,Req1,Resp1>
  {
  static void validate_core(const Req1& request);
  static Resp1* process_core(const Req1& request);
  friend handler_base;
  };

 template<>
 class handler<Req2,Resp2>
  : handler_base<handler<Req2,Resp2>,Req2,Resp2>
  {
  friend handler_base;
  static Resp2* process_core(const Req2& request);
  };
//just to force compilation
template Resp2* handler_base<handler<Req2,Resp2>,Req2,Resp2>::process(const Req2&);
template Resp1* handler_base<handler<Req1,Resp1>,Req1,Resp1>::process(const Req1&);

答案 1 :(得分:-1)

  

目前我的解决方法是为validate_core提供一个默认的空实现,如果它不是专用的,则调用一个空方法。我想知道是否有更好的方法。

在我看来,这是一个非常好的方式。

不确定您的要求,但我想您可以删除validate_core()

的模板版本
  template <typename TRq = TRequest>
  static void validate_core (TRequest const &) = delete;

并在handler的正文内启用一个或多个非模板专精

  static void validate_core (int const &)
   { /* do something */ }

  static void validate_core (long const &)
   { /* do something */ }

  // ...

接下来,您可以在handler的正文中添加一个类型特征,以检测它是否可用于validate_core()

的专业化
  template <typename, typename = void>
  struct withValidateCore : public std::false_type
   { };

  template <typename T>
  struct withValidateCore<T, decltype(validate_core(std::declval<T>()))>
     : public std::true_type
   { };

如果您可以使用C ++ 17,这种方式可能会很有趣,因为它可用if constexpr (),所以应该可以这样做[抱歉:未经测试]

static TResponse process (TRequest const & request)
 {
   if constexpr ( withValidateCore<TRequest>::value )
    {
       log("begin validate");
       validate_core(request);
    }

   return process_core(request);
 }

但您标记了C ++ 14,因此if constexpr ()不可用,我看到使用withValidateCore的最佳方式是实现两个不同的(SFINAE启用/禁用)版本的{{ 1}};

之类的东西
process()

否则(可能会好一点)基于标签调度的东西

  template <typename TRq = TRequest>
  static std::enable_if_t<(true == withValidateCore<TRq>{})
        && (true == std::is_same<TRq, TRequest>{}), TResponse>
     process (TRequest const & request)
   {
     validate_core(request);

     return process_core(request);
   }

  template <typename TRq = TRequest>
  static std::enable_if_t<(false == withValidateCore<TRq>{})
        && (true == std::is_same<TRq, TRequest>{}), TResponse>
     process (TRequest const & request)
   { return process_core(request); }

恕我直言,基于空private: static TResponse process (TRequest const & request, std::true_type const &) { validate_core(request); return process_core(request); } static TResponse process (TRequest const & request, std::false_type const &) { return process_core(request); } public: static TResponse process (TRequest const & request) { return process(request, withValidateCore<TRequest>{}); } 的通用版本的解决方案更好(在C ++ 14中)。

无论如何,以下是一个完整的工作示例

validate_core()