Частичная специализация шаблона: сопоставление по свойствам специализированного параметра шаблона - PullRequest
3 голосов
/ 29 мая 2010
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

Редактировать в ответ на In silico : Я сказал, что было бы неплохо сделать 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;
};

Ответы [ 4 ]

4 голосов
/ 29 мая 2010

Понятия не имею, что вы имеете в виду. Параметры шаблона шаблона кажутся решением, хотя вы как-то говорите, что они не будут работать. Почему бы не сделать это?

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

И все же я не совсем понимаю, что ты имеешь в виду.

0 голосов
/ 29 мая 2010

Это то, что вы хотите? (Протестировано с 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"
}

Ваша попытка частичной специализации вызывает ошибки компилятора, потому что вы можете передать только templates к параметрам шаблона шаблона. Вы не можете передать template <> class B<P2> для параметра шаблона шаблона, потому что это полный тип, а не шаблон.

Для первых двух строк кода в функции main() C - это полный тип, который мы передаем в A ' type параметр X. B - это шаблон, который мы передаем A шаблон параметр Y, и этот шаблон должен принимать Property в качестве единственного параметра шаблона. Мы передаем Property значение (P1 или P2) A не типу параметр P отдельно. Когда мы передаем P2 для последнего аргумента шаблона A, компилятор увидит специализацию и будет использовать ее, иначе компилятор будет использовать основной шаблон A. Аналогичная схема следует для следующих 6 строк.

0 голосов
/ 29 мая 2010

Я собираюсь предоставить другой ответ в ответ на ваш комментарий с примером 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, будут специализированными.Надеюсь, это поможет, по крайней мере, немного.: -)

0 голосов
/ 29 мая 2010

Без параметров шаблона шаблона (которые я не знаю, чтобы использовать в этом контексте), это должно быть довольно просто:

template <> class A<C, B<P2> > { ... };

Слишком просто, на самом деле. Должно быть, я что-то упустил, но я не вижу, что.

...