Частичная специализация шаблона: сопоставление о свойствах специализированного параметра шаблона
-
05-10-2019 - |
Вопрос
template <typename X, typename Y> class A {
// Use Y::Q, a useful property, not used for specialization.
};
enum Property {P1,P2};
template <Property P> class B {};
class C {};
Есть ли способ определить частичную специализацию A
Такое это A<C, B<P1> >
было бы A
нормальный шаблон, но A<C, B<P2> >
будет специализация?
Редактировать в ответ на Марсело: Более конкретно, специализация должна быть выбрана не только с B, но с любым типом, который демонстрирует определенное свойство, например, что это шаблон, первый аргумент которого является P2.
Цель состоит в том, чтобы использовать Y
Представить хороший интерфейс для A
, позволяя написать что-то вроде A<C, Y<P2,Q> >
.
Замена Y
Параметр шаблона по параметру шаблона шаблона был бы приятно, но есть ли способ частично специализироваться на его основе P
тогда?
Намерение было бы написать что-то вроде:
template <typename X, template <Property P> typename Y> class A {};
template <typename X> class A<X,template<> Y<P2> > {}; // <-- not valid
Редактировать в ответ на силико: Я сказал, что было бы неплохо сделать Y
параметр шаблона шаблона, но на самом деле, который поражает цель того, что я хотел сделать, то есть использовать Y
группу логически связанные свойства вместе, но все же специализируются A
на основе одного из этих подразвей свойств.
Есть ли способ, добавляя чеши к специализации template <> class B<P2>
а затем используете Sfinae в A
? Намерение было бы написать что-то вроде:
template <> class B<P2> {
typedef int IAmP2;
};
// The following is not valid because it's a simple redefinition.
template <typename X, typename Y> class A {
// Substitution using this template would fail for Y<P1>, and only the
// general template would be left for selection.
typename Y::IAmP2 skipIfNotP2;
};
Решение
Я понятия не имею, что вы имеете в виду. Параметры шаблона шаблона кажутся решением, хотя вы как-то сказать, что они не будут работать. Почему бы не сделать это?
template <typename X, typename Y>
class A {
};
template <typename X, template<typename> class Y, typename P>
class A< X, Y<P> > {
/* property is P */
};
Для вашего вопроса Sfinae, да, это тоже возможно
template <typename X, typename Y, typename Sfinae = void>
class A {
};
template <typename X, typename Y>
class A< X, Y, typename Y::IAmP2 > {
/* Y is the class having a property */
};
class Sample {
typedef void IAmP2;
};
Тем не менее я не уверен, что вы имеете в виду вообще.
Другие советы
Без шаблона шаблона параметров (которые я не знал, чтобы использовать в этом контексте), он должен быть довольно простым:
template <> class A<C, B<P2> > { ... };
Слишком просто, на самом деле. Я должен пропустить что-то, но я не вижу, что.
Это то, что вы хотите? (Испытано с Visual Studio 2005)
enum Property { P1, P2 };
template <Property P> class B {};
class C {};
// Other similar types, for the purpose of testing
template <Property P> class AnotherB {};
class AnotherC {};
// Primary template
template <typename X, template<Property P> class Y, Property P> class A
{
public:
A() { ::printf("Primary template\n"); }
};
// Partial specialization for P2
template <typename X, template<Property P> class Y> class A<X, Y, P2>
{
public:
A() { ::printf("Partially specialized template\n"); }
};
int main()
{
// Trying out some combinations
A<C, B, P1> q; // prints "Primary template"
A<C, B, P2> w; // prints "Partially specialized template"
A<AnotherC, B, P1> e; // prints "Primary template"
A<AnotherC, B, P2> r; // prints "Partially specialized template"
A<C, AnotherB, P1> t; // prints "Primary template"
A<C, AnotherB, P2> y; // prints "Partially specialized template"
A<AnotherC, AnotherB, P1> u; // prints "Primary template"
A<AnotherC, AnotherB, P2> i; // prints "Partially specialized template"
}
Ваша попытка частичной специализации вызывает ошибки компилятора, потому что вы можете пройти толькошаблоны шаблон шаблона параметров. Вы не можете пройти template <> class B<P2>
Для параметра шаблона шаблона, потому что это полный тип, а не шаблон.
Для первых двух строк кода в main()
функция, C
это полный тип, к которому мы проходим A
С. тип параметр X
. B
шаблон, в котором мы передаем A
С. шаблон параметр Y
, и этот шаблон должен принять Property
как единственный параметр шаблона. Мы проходим в Property
ценность (тоже P1
или P2
) к A
С. неисполнительно параметр P
отдельно. Когда мы проходим в P2
Для последнего аргумента шаблона A
, Компилятор увидит специализацию и использовать это - в противном случае компилятор будет использовать основной шаблон A
. Отказ Аналогичная картина следует для следующих 6 строк.
Я собираюсь предоставить другой ответ в ответ на ваш комментарий с Matrix
пример.
Для тебя Matrix
Пример, вы можете сделать это:
enum MatrixOrder { ColumnMajor, RowMajor };
template<MatrixOrder Order> class Dense {};
template<MatrixOrder Order> class Sparse {};
template<typename T, template<MatrixOrder> class Storage, MatrixOrder Order>
class Matrix
{
public:
Matrix() { ::printf("Primary\n"); }
};
template<typename T, MatrixOrder Order>
class Matrix<T, Dense, Order>
{
public:
Matrix() { ::printf("Specialized\n"); }
};
int main()
{
// Trying out some combinations...
Matrix<double, Dense, ColumnMajor> a; // Prints "Specialized"
Matrix<double, Dense, RowMajor> b; // Prints "Specialized"
Matrix<double, Sparse, ColumnMajor> c; // Prints "Primary"
Matrix<double, Sparse, RowMajor> d; // Prints "Primary"
Matrix<float, Dense, ColumnMajor> e; // Prints "Specialized"
Matrix<float, Dense, RowMajor> f; // Prints "Specialized"
Matrix<float, Sparse, ColumnMajor> g; // Prints "Primary"
Matrix<float, Sparse, RowMajor> h; // Prints "Primary"
return 0;
};
Требуется подобное шаблон моему последнему ответу. Теперь все схемы хранения принимают Dense
будет специализироваться. Надеюсь, это поможет, по крайней мере, немного. :-)