2016-04-20 5 views
1

я классы свойств посыпают о моем коде, которые следуют один и тот же основной идиомы:Черты характера класса в качестве параметра шаблона шаблон

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 стало полезным для нескольких концепций в моем коде, и я хотел бы обобщить его дальше, так что я могу передать класс черты в качестве дополнительного параметра:

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.

Я знаю, что я мог бы обойти эту проблему, если я всегда использую класс черты в шаблоне конкретизации (и изменить признак проверку, чтобы принять его), а именно

has_base_frame_type<frame_traits<MyClass>>::value 

, но я не хочу делать это, потому что было бы all too easy забыть и пройти в классе без признаков. Фактически, именно так я изначально написал код, пока я не забыл эту черту слишком много раз и реорганизовал ее.

Есть ли какой-нибудь способ изменить свой класс idiom, чтобы обойти проблему с шаблоном шаблона шаблона?

+0

Что-то вроде [идиомы обнаружения] (http://coliru.stacked-crooked.com/a/779edd372df54f26)? –

+0

@Piotr Я не очень хорошо читаю метакод шаблона, но я не уверен, что ваши псевдонимы черт имеют те же свойства, что и мой класс признаков, а typedef всегда будет определен независимо от того, какой ввод шаблона, но будет недействительным если typedef не был определен 'T'. Кроме того, для меня не очевидно, что он масштабирует классы признаков, которые определяют несколько типов typedef. –

+0

Вы имеете в виду [это] (http://coliru.stacked-crooked.com/a/0108aa409e8e95fe)? Что вы подразумеваете под словом «оно не масштабируется»? Зачем вам нужен фиктивный 'void' typedef, если это просто черта? –

ответ

2

Framework:

#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 
} 

DEMO