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的模板
目标是使用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>
中添加特征,然后在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;
};
答案 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)
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
的类型参数的完整类型X
。 B
是我们传递给A
的模板参数Y
的模板,该模板必须接受Property
作为只有模板参数。我们将Property
值(P1
或P2
)分别传递给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
的存储方案都将是专用的。希望这有助于,至少一点点。 : - )