部分模板专业化:匹配专用模板参数的属性

时间:2010-05-29 06:13:04

标签: c++ sfinae partial-specialization template-templates

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> >是专业化的?

编辑以响应Marcelo :更具体地说,专业化不仅应该选择B,而且应该选择具有特定属性的任何类型,例如它是第一个参数为P2的模板

目标是使用YA提供一个很好的界面,允许编写类似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>中添加特征,然后在A中使用SFINAE?目的是写下这样的东西:

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 个答案:

答案 0 :(得分: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;
};

我仍然不确定你的意思。

答案 1 :(得分:0)

没有模板模板参数(我不知道在此上下文中使用),它应该相当简单:

template <> class A<C, B<P2> > { ... };
事实上,太简单了。我一定错过了什么,但我看不清楚。

答案 2 :(得分: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"
}

您尝试部分特化会导致编译器错误,因为您只能传递 templates 到模板模板参数。您无法传递template <> class B<P2>作为模板模板参数,因为它是完整类型,而不是模板。

对于main()函数中的前两行代码,C是我们传递给A类型参数的完整类型XB是我们传递给A模板参数Y的模板,该模板必须接受Property作为只有模板参数。我们将Property值(P1P2)分别传递给A非类型参数P。当我们传递P2以获取模板A的最后一个参数时,编译器将看到特化并使用它 - 否则,编译器将使用主模板A。接下来的6行也会出现类似的模式。

答案 3 :(得分:0)

我将使用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的存储方案都将是专用的。希望这有助于,至少一点点。 : - )