2015-02-02 2 views
5

Рассмотрят шаблон класса и вспомогательные классы перечислений определена следующим образом:шаблона класса, который не зависит от перестановок аргументов

enum class Color {Red, Green, Blue} 
enum class ShowAxes {False, True} 
enum class ShowLabels {False, True} 

template< Color, ShowAxes, ShowLabels > 
class A 
{......}; 

Вопрос в том, как переопределить класс А, который был бы независимым от перестановки его аргументов. Я использую Dev C++, который поддерживает C++ 11.

[EDIT]

Например, новая версия должна поддерживать

A< Color::Red, ShowAxes::True, ShowLabels::True > 
A< Color::Red, ShowLabels::True, ShowAxes::True > 
A< ShowAxes::True, Color::Red, ShowLabels::True > 
A< ShowLabels::True, Color::Red, ShowAxes::True > 
A< ShowLabels::True, Color::Red, ShowAxes::True > 
A< ShowAxes::True, Color::Red, ShowLabels::True > 

версии, и все они идентичны, то они порождают один и тот же класс.

+0

C++ шаблона класса специализации? –

+1

@BryanChen вы не можете изменять типы параметров со специализацией –

+0

Я не хочу менять типы параметров. Специализация - хорошая идея, но у меня есть 3! = 6 перестановок. Более того, я собираюсь добавить дополнительные параметры. –

ответ

5

Это невозможно в вашем текущем интерфейсе с использованием параметров, отличных от типа.

Вы можете принять параметры типа вместо и завернуть значения в std::integral_constant:

template<class X, class Y, class Z> 
class A { /* stuff */ }; 

// use as: 
A<std::integral_constant<Color, Color::Red>, 
    std::integral_constant<ShowAxes, ShowAxes::True>, 
    std::integral_constant<ShowLabels, ShowLabels::True>> a; 

Это довольно многословен, так что вы могли бы рассмотреть возможность написания макроса:

#define AS_IC(Value) std::integral_constant<decltype(Value), Value> 

и переписать в виде

A<AS_IC(Color::Red), AS_IC(ShowAxes::True), AS_IC(ShowLabels::True)> a; 

Извлечение значения нужного типа из спискаs прост:

template<class Result, class...> 
struct extract; 

template<class Result, Result Value, class... Tail> 
struct extract<Result, std::integral_constant<Result, Value>, Tail...> : std::integral_constant<Result, Value> {}; 

template<class Result, class Head, class... Tail> 
struct extract<Result, Head, Tail...> : extract<Result, Tail...> {}; 

Затем вы можете сделать

// inside the definition of A 
static constexpr Color col = extract<Color, X, Y, Z>::value; 

Demo.

Это не, однако, порождают один и тот же класс, но вы можете сделать шаблон A_impl класс, который ведет себя, как ваш A с параметрами не типа, и содержит фактическую реализацию, а затем сделать A шаблон псевдоним:

template< Color, ShowAxes, ShowLabels > 
class A_impl 
{/* stuff */}; 

template<class X, class Y, class Z> 
using A = A_impl<extract<Color, X, Y, Z>::value, 
       extract<ShowAxes, X, Y, Z>::value, 
       extract<ShowLabels, X, Y, Z>::value>; 

Теперь данный

A<AS_IC(Color::Red), AS_IC(ShowAxes::True), AS_IC(ShowLabels::True)> a; 
A<AS_IC(Color::Red), AS_IC(ShowLabels::True), AS_IC(ShowAxes::True)> b; 

a и b имеют одинаковый тип. Demo.

В качестве альтернативы, вы можете также использовать decltype и перегружать шаблоны функций, но это требует добавления шаблона объявление функции для каждого возможного порядка типов:

template< Color c, ShowAxes a, ShowLabels l> 
A<c,a,l> A_of(); 

template< ShowAxes a, ShowLabels l, Color c> 
A<c,a,l> A_of(); 

// etc. 

decltype(A_of<Color::Red, ShowAxes::True, ShowLabels::True>()) a1; 
decltype(A_of<ShowAxes::True, ShowLabels::True, Color::Red>()) a2; 
+0

Идея 'std :: integral_constant' и' extract' выглядит неплохо. Я подумаю об оптимизации кода. –

+0

У меня есть небольшой (возможно, тривиальный) вопрос. Можно ли заменить макрос AS_IC не директивным персоналом, скажем, шаблон класса или функцию шаблона? –

+1

@VahagnPoghosyan Без макро-свободного способа, о котором я знаю, без добавления большого количества шаблонов, когда вы объявляете 'A'. –

0

Возможно, используя std::is_same. После этого вы можете упростить ваш код таким образом:

template <typename A, typename B, typename C> 
class X 
{ 
public: 
    X() { 
     static_assert(
      std::is_same<A, Color>::value || 
      std::is_same<B, Color>::value || 
      std::is_same<C, Color>::value, 
      "nope"); 
     // other assertions here! 
     // also, make sure your types are different ;) 
    } 
    X(A a, B b, C c) : X() { 
     // your code here 
    } 
}; 

template <typename A, typename B, typename C> 
X<A, B, C> make(A a, B b, C c) { 
    // possible verifications here 
    return X<A, B, C>(a, b, c); 
} 

int main() { 
    auto a = make(Color::Red, ShowAxes::true, ShowLabels::True); 
    return 0; 
} 

Вы можете проверить все ваши типы A, B & C.

Мне очень жаль, но я не вижу никакого другого решения. :/

+2

Код OP ожидает параметры шаблона непигового типа –

+0

Я добавил текст в вопрос для подробного объяснения моей цели. –

+0

Я отредактировал мое сообщение. – vincentp

Смежные вопросы