Partial Template Specialization: Mapping Properties of a Custom Template Parameter

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

Is there a way to define a partial specialization Asuch that it A<C, B<P1> >will be a Anormal template, but A<C, B<P2> >will be a specialization?

Change in response to Marcelo: In particular, specialization should be chosen not only with B, but also with any type that demonstrates a certain property, for example, that this is a template whose first argument is P2.

The goal is to use Yto present a nice interface for Aallowing you to write something like A<C, Y<P2,Q> >.


Replacing the template Yparameter with the template template parameter will be nice, but is there a way to partially specialize it on the basis P, and then?

The intention would be to write something like:

template <typename X, template <Property P> typename Y> class A {};
template <typename X> class A<X,template<> Y<P2> > {}; // <-- not valid

Edit in response to In silico: I said that it would be nice to make Ya template template parameter, but in fact it wins the goal of what I wanted to do, namely to use Ylogically related properties together for grouping, but still specialize Ain basis of one of these sub-properties.


Is there a way by adding traits to the specialization template <> class B<P2>and then using SFINAE's A? The intention would be to write something like:

template <> class B<P2> {
    typedef int IAmP2;
};

// The following is not valid because it 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;
};
+3
4

, . , - , . ?

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

, .

+4

( , ), :

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

, . - , , .

0

, ? ( 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 type X. B - , A Y, Property . Property ( P1 P2) A nontype P . P2 A, , A. 6 .

0

Matrix.

For example, Matrixyou can do this:

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

For my last answer, it adopts a similar model. Now all storage schemes using Densewill be specialized. Hope this helps, at least a little. :-)

0
source

Source: https://habr.com/ru/post/1747647/


All Articles