我有一个由带有静态成员函数的模板模板类参数化的类:
template <template <typename> class F>
struct A {
static int foo();
};
此类没有foo
的默认定义,并且必须专门用于其他类型。
我还有另一个类,它是由带有嵌套模板类的模板模板类参数化的:
template <template <typename> class F>
struct B {
template <typename T>
struct C {};
};
我希望C
专用于A
的任何已专门化F
的模板模板类A
:
template <template <typename> class F>
struct A<B<F>::template C> {
static int foo();
};
template <template <typename> class F>
int A<B<F>::template C>::foo() {
return A<F>::foo() / 2;
}
因此,如果我有一个专门研究A
的课程:
template <typename T>
struct E {};
template <>
int A<E>::foo() {
return 42;
}
我希望能够使用这样的专业化(并返回21):
int bar() {
return A<B<E>::template C>::foo();
}
但是,这无法链接-找不到对A<B<E>::C>::foo()
的引用。
(请注意,所有这些都在一个文件中-此处的标头没有发生奇怪的事情)
似乎编译器正在尝试将主模板用于A
而不是专门化,这意味着foo
是未定义的。为什么在这种情况下不使用专业化?
template <template <typename> class F>
struct A {
static int foo();
};
template <template <typename> class F>
struct B {
template <typename T>
struct C {};
};
template <template <typename> class F>
struct A<B<F>::template C> {
static int foo();
};
template <template <typename> class F>
int A<B<F>::template C>::foo() {
return A<F>::foo() / 2;
}
template <typename T>
struct E {};
template <>
int A<E>::foo() {
return 42;
}
int bar() {
// Link fails - error: undefined reference to 'A<B<E>::C>::foo()'
return A<B<E>::template C>::foo();
}
答案 0 :(得分:5)
template<class T>
struct A {};
template<class T>
struct B {
using type=T;
};
template<class T>
struct A<typename B<T>::type> {};
这基本上是相同的,但是模板层少了一层。
这也不起作用。
问题是B<T>::type
或B<T>::template Z
或在一般情况下是任意的编译时函数。
并且为了对其进行模式匹配,我们需要反转此任意编译时间函数。
该标准说“编译器不必这样做”,这是您可以在此处执行的几项理智的操作之一。它肯定是针对类型的。对于模板来说,模板的模板参数的标准措辞通常缺少细节,因此,如果措辞缺失,我也不会感到惊讶。但是,如果没有,那就是标准中的错误。
为了出发
template<class T>
struct A<typename B<T>::type> {};
要查看A<foo>
是否与之匹配,就必须测试所有类型的T
,以查看其中哪些类型的B<T>::type
等于foo
。
这可能不是您要表达的意思,但这就是您要的内容。
您的模板示例也是如此。
template <template <typename> class F>
struct A<B<F>::template C> {
static int foo();
};
您正在要求编译器检查每种类型的F
,以便如果将其传递给任意模板B<>
然后对其求值::C
,该模板是否与您的模板匹配传递A
。
第一个有趣的案例:
template<class X>
struct C0 {};
template <template <typename> class F>
struct B {
template <typename T>
using C=C0<X>:
};
现在,F
中的A<C0>
是什么?每个F
都符合条件。
template<class X>
struct C0 {};
template <template <typename> class F, class=void>
struct B {
template <typename T>
using C=C0<X>:
};
template<class X>
struct C1 {};
template <template <typename> class F, class=void>
struct B<
F,
std::enable_if_t<
proves_collatz_conjecture( F<int>::value )
>
> {
template <typename T>
using C=C1<T>;
};
现在要模式化A<C0>
,编译器必须产生F
,以使F<int>::value
是编译时类型,当传递给proves_collatz_conjecture
时返回true
在编译时。
那会很有用。
模板专业化是模式匹配。在C ++中,您无法对依赖类型(也可能是模板)进行模式匹配,因为类型和模板都没有超出其值的标识。
您无法检查定义了变量,类型或模板的范围。因此,也无法对其进行模式匹配。
如果您想做自己想做的事,模板C
本身就具有可以检查和测试的属性。