10

比较班级template专业化的程序是什么?该标准在这一点上没有详细说明(或者我错过了正确的地方)。
我的问题与决定在实例化期间使用什么专业无关。请不要对此发表评论。问题是关于相互比较专业化以确定特定专业化是否已经定义。

考虑这个示例代码:

template <class x1, class x2>
struct CoreTemplate { };

template <class x1, class x2>
struct CoreTemplate<x1*, x2*> { int spec; CoreTemplate() { spec = 1; } };

template <class x1, class x2>
struct CoreTemplate<x2*, x1*> { int spec; CoreTemplate() { spec = 2; } };

int main(int argc, char* argv[])
{
    CoreTemplate<int*, int*> qq;
    printf("var=%d.\r\n", qq.spec);
}

当我尝试使用 MSVC 编译此代码时,我在函数内部尝试实例化时收到错误消息main

cpptest1.cxx(15) : 错误 C2752: ' CoreTemplate<x1,x2>' : 多个部分特化匹配模板参数列表

对我来说,尝试声明相同的模板特化时发出错误会更合乎逻辑。我看不出上面的专业有什么区别。

那么,有人知道比较模板专业化的规则吗?文章、链接、书籍等也会有所帮助。

4

3 回答 3

5

该标准特别指出这仅在您尝试实例化模板时发生(第 14.5.4.1/1 节):

当在需要类实例化的上下文中使用类模板时,有必要确定是使用主模板还是部分特化生成实例化。[重点补充]

不幸的是,如果不讨论如何决定在实例化期间使用哪种专业化,就无法回答您的其余问题。这是标准中的文本(继续上面的摘录):

这是通过将类模板特化的模板参数与部分特化的模板参数列表匹配来完成的。

  • 如果恰好找到一个匹配的特化,则从该特化生成实例化。
  • 如果找到多个匹配的特化,则使用偏序规则 (14.5.4.2) 来确定其中一个特化是否比其他特化更特化。如果没有一个特化比所有其他匹配的特化更特化,那么类模板的使用是模棱两可的并且程序是非良构的。

因此,它甚至根本不会尝试直接将模板相互比较。相反,它试图找到与给定参数匹配的专业化。如果有多个匹配项,它会尝试根据部分排序规则选择最专业的一个。如果两者都不比另一个更专业,则实例化是不明确的,并且编译失败。

现在,确实不能使用这两种专业化,因为总会有歧义——如果任何一个匹配,另一个显然同样匹配。不过,编译器根本不需要检测或诊断它。在这种确切的情况下(基本上相同的专业化)可能很容易,但几乎可以肯定在其他情况下它会困难得多,因此(显然)委员会决定编译器甚至不必尝试。

于 2012-06-21T06:47:14.333 回答
1

啊,但是它们一样,因为它们不使用相同的参数。使用 clang 和您的原始示例:

#include <cstdio>

template <class x1, class x2>
struct CoreTemplate { };

template <class x1, class x2>
struct CoreTemplate<x1*, x2*> { int spec; CoreTemplate() { spec = 1; } };
// note: partial specialization matches [with x1 = int, x2 = int]

template <class x1, class x2>
struct CoreTemplate<x2*, x1*> { int spec; CoreTemplate() { spec = 2; } };
// note: partial specialization matches [with x1 = int, x2 = int]

int main()
{
    CoreTemplate<int*, int*> qq;
    // error: ambiguous partial specializations of 'CoreTemplate<int *, int *>'
    std::printf("var=%d.\r\n", qq.spec);
}

但是,如果我们调整部分特化以使它们完全匹配:

template <class x1, class x2>
struct Core { };

template <class x1>
struct Core<x1*, x1*> { int spec; Core() { spec = 1; } };
// note: previous definition is here

template <class x1>
struct Core<x1*, x1*> { int spec; Core() { spec = 2; } };
// error: redefinition of 'Core<type-parameter-0-0 *, type-parameter-0-0 *>'

因此,这似乎只是一个实施质量问题。编译器可能会针对第一种情况发出警告,但在一般情况下它可能会消耗资源,或者可能只是到目前为止没有人表示需要。

于 2012-06-21T06:54:46.980 回答
0

对我来说,尝试声明相同的模板特化时发出错误会更合乎逻辑。

这不会发生,因为CoreTemplate<int*, double*>并且CoreTemplate<double*, int*>会生成不同的类型。

以下是我的猜测:
编译器可能不会对身体进行额外的理智/常识检查。 实例化 a后,编译器会查找匹配的类型并选择最好的类型。如果它不只匹配one,那么它会给出no-matchmultiple-match的编译器错误。template
template

例如:

template<typename T>
void foo ()
{
  T::x();
}

int main ()
{
}

编译得很好,即使我们知道在整个 C++ 程序中没有一个函数名x()。只有当您尝试实例化foo<T>.

此外,如果您通过在两个专业之间放置一点来扭曲您的示例main(),它将编译得非常好

于 2012-06-21T06:26:16.793 回答