Traits class 作为模板模板参数
Traits class as a template template parameter
我的代码具有 class 的特征,它们遵循相同的基本习惯用法:
template<class Frame, typename = void>
struct frame_traits
{
typedef void base_frame_type;
};
template<class Frame>
struct frame_traits<Frame, typename std::void_t<
typename Frame::base_frame_type>::type>
{
typedef typename Frame::base_frame_type base_frame_type;
};
我有一堆使用它们的特征检查器,它们也遵循类似的习惯用法:
template <typename T>
struct has_base_frame_type : std::integral_constant<bool,
!std::is_same<typename frame_traits<T>::base_frame_type, void>::value>::type {};
然而,事实证明 has_base_frame_type
对我的代码中的多个概念很有用,我想进一步概括它,以便我可以将特征 class 作为附加参数传递参数:
template <typename T, template<typename> class Traits = frame_traits>
struct has_base_frame_type : std::integral_constant<bool,
!std::is_same<typename Traits<T>::base_frame_type, void>::value>::type {};
虽然这不起作用,因为 templates with default arguments cannot be used as template template parameters。
我知道我可以解决这个问题,如果我总是在模板实例化中使用特征 class(并修改特征检查器以接受它),即
has_base_frame_type<frame_traits<MyClass>>::value
但我不想那样做,因为忘记并传入非特征 class 会是 all too easy。事实上,这就是我最初编写代码的方式,直到我多次忘记该特征并重构它。
有什么方法可以修改我的 trait class 习语来解决模板模板参数问题吗?
框架:
#include <type_traits>
template <typename...>
using void_t = void;
template <typename AlwaysVoid, template <typename...> class Operation, typename... Args>
struct detect_impl : std::false_type {};
template <template <typename...> class Operation, typename... Args>
struct detect_impl<void_t<Operation<Args...>>, Operation, Args...> : std::true_type {};
template <template <typename...> class Operation, typename... Args>
using detect = detect_impl<void, Operation, Args...>;
检测器:
template <class Frame>
using frame_traits = typename Frame::base_frame_type;
template <class Frame>
using other_frame_traits = typename Frame::other_frame_type;
具有默认检测器的特征:
template <typename T, template <typename...> class Traits = frame_traits>
using has_frame_type = detect<Traits, T>;
测试:
struct A
{
using base_frame_type = void;
};
struct B
{
using other_frame_type = void;
};
int main()
{
static_assert(has_frame_type<A>{}, "!"); // default
static_assert(!has_frame_type<B>{}, "!"); // default
static_assert(!has_frame_type<A, other_frame_traits>{}, "!"); // non-default
static_assert(has_frame_type<B, other_frame_traits>{}, "!"); // non-default
}
我的代码具有 class 的特征,它们遵循相同的基本习惯用法:
template<class Frame, typename = void>
struct frame_traits
{
typedef void base_frame_type;
};
template<class Frame>
struct frame_traits<Frame, typename std::void_t<
typename Frame::base_frame_type>::type>
{
typedef typename Frame::base_frame_type base_frame_type;
};
我有一堆使用它们的特征检查器,它们也遵循类似的习惯用法:
template <typename T>
struct has_base_frame_type : std::integral_constant<bool,
!std::is_same<typename frame_traits<T>::base_frame_type, void>::value>::type {};
然而,事实证明 has_base_frame_type
对我的代码中的多个概念很有用,我想进一步概括它,以便我可以将特征 class 作为附加参数传递参数:
template <typename T, template<typename> class Traits = frame_traits>
struct has_base_frame_type : std::integral_constant<bool,
!std::is_same<typename Traits<T>::base_frame_type, void>::value>::type {};
虽然这不起作用,因为 templates with default arguments cannot be used as template template parameters。
我知道我可以解决这个问题,如果我总是在模板实例化中使用特征 class(并修改特征检查器以接受它),即
has_base_frame_type<frame_traits<MyClass>>::value
但我不想那样做,因为忘记并传入非特征 class 会是 all too easy。事实上,这就是我最初编写代码的方式,直到我多次忘记该特征并重构它。
有什么方法可以修改我的 trait class 习语来解决模板模板参数问题吗?
框架:
#include <type_traits>
template <typename...>
using void_t = void;
template <typename AlwaysVoid, template <typename...> class Operation, typename... Args>
struct detect_impl : std::false_type {};
template <template <typename...> class Operation, typename... Args>
struct detect_impl<void_t<Operation<Args...>>, Operation, Args...> : std::true_type {};
template <template <typename...> class Operation, typename... Args>
using detect = detect_impl<void, Operation, Args...>;
检测器:
template <class Frame>
using frame_traits = typename Frame::base_frame_type;
template <class Frame>
using other_frame_traits = typename Frame::other_frame_type;
具有默认检测器的特征:
template <typename T, template <typename...> class Traits = frame_traits>
using has_frame_type = detect<Traits, T>;
测试:
struct A
{
using base_frame_type = void;
};
struct B
{
using other_frame_type = void;
};
int main()
{
static_assert(has_frame_type<A>{}, "!"); // default
static_assert(!has_frame_type<B>{}, "!"); // default
static_assert(!has_frame_type<A, other_frame_traits>{}, "!"); // non-default
static_assert(has_frame_type<B, other_frame_traits>{}, "!"); // non-default
}