假设我有一个这样的模板类:
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
提供一个默认的空实现,如果它不是专门的,则会调用一个空方法。我想知道是否有更好的方法。
最佳答案
Currently my workaround is giving a default empty implementation to validate_core, if it's not specialized then an empty method is invoked. I want to know if there is a better way.
在我看来这是一个很好的方法。
不确定是否理解您的要求,但我想您可以删除 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/disabled) 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); }
否则(也许更好一点)一些基于标签分派(dispatch)的东西
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>{}); }
恕我直言,基于 validate_core()
的空泛型版本的解决方案(在 C++14 中)更好。
无论如何,下面是一个完整的工作示例
#include <iostream>
#include <type_traits>
template <typename TRequest, typename TResponse = void>
class handler
{
private:
template <typename TRq = TRequest>
static void validate_core (TRequest const &) = delete;
static void validate_core (int const &)
{ std::cout << "- validate_core() int case" << std::endl; }
static void validate_core (long const &)
{ std::cout << "- validate_core() long case" << std::endl; }
static TResponse process_core (const TRequest &)
{ return TResponse(); }
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
{ };
public:
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); }
};
int main()
{
handler<int>::process(0); // print - validate_core() int case
handler<int, long>::process(0); // print - validate_core() int case
handler<long>::process(0); // print - validate_core() long case
handler<char>::process(0); // no print
}
关于c++ - 检查方法的模板特化是否存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47747271/