未定义对专业模板成员的引用

时间:2018-08-27 18:47:51

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

我有一个由带有静态成员函数的模板模板类参数化的类:

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

1 个答案:

答案 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>::typeB<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本身就具有可以检查和测试的属性。