为什么编译器在定义类似的模板专用化时不会出错?
Why compiler doesn't give error while defining similar template specializations?
比较班级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.rn", qq.spec);
}
当我尝试使用 MSVC 编译此代码时,我在 main
函数内出现实例化尝试的错误:
cpptest1.cxx(15):错误 C2752: '
CoreTemplate<x1,x2>
' : 多个部分专用化与模板参数列表匹配
对我来说,为尝试声明相同的模板专业化而发出错误会更合乎逻辑。我认为上述专业之间没有任何区别。
那么,有人知道比较模板专业化的规则吗?文章、链接、书籍等也会有所帮助。
该标准明确指出,这仅在您尝试实例化模板时发生 (§14.5.4.1/1):
在需要类实例化的上下文中使用类模板时,有必要确定是使用主模板还是使用部分专用化之一生成实例化。[着重号后加]
不幸的是,如果不讨论如何决定在实例化期间使用哪种专用化,就无法回答其余的问题。以下是标准中的文本(继续上面的摘录):
这是通过将类模板专用化的模板参数与部分专用化的模板参数列表进行匹配来完成的。
- 如果只找到一个匹配的专用化,则会从该专用化生成实例化。
- 如果找到多个匹配的专用化,则使用偏序规则 (14.5.4.2) 来确定其中一个专用化是否比其他专用化更专业。如果没有一个专用化比所有其他匹配的专用化更专业,则类模板的使用是不明确的,并且程序格式不正确。
因此,它甚至从未尝试将模板直接相互比较。相反,它试图找到一种与给定参数相匹配的专业化。如果有多个匹配,它将尝试根据部分排序规则选择最专业的一个。如果两者都不比另一个更专业,则实例化不明确,编译失败。
现在,这些专业都不能使用,因为总是会有歧义 - 如果任何一个匹配,另一个显然同样匹配。不过,编译器根本不需要检测或诊断这一点。在这种确切的情况下(本质上相同的专业),这可能很容易,但几乎可以肯定的是,在其他情况下会困难得多,所以(显然)委员会决定编译器甚至不必尝试。
啊,但它们不一样,因为它们不使用相同的参数。使用 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.rn", 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 *>'
因此,这似乎只是一个实施质量问题。编译器可能会针对第一种情况发出警告,但在一般情况下可能会消耗资源,或者可能只是到目前为止没有人表示需要。
对我来说,为尝试发出错误会更合乎逻辑 声明相同的模板专用化。
这不会发生,因为
CoreTemplate<int*, double*>
和CoreTemplate<double*, int*>
将生成不同的类型。
以下是我的猜测:
编译器可能不会对template
正文进行额外的理智/常识性检查。
一旦你实例化了一个template
,编译器就会查找匹配的类型并选择最好的类型。如果它不只匹配一个,则它会为不匹配或多重匹配提供编译器错误。
例如:
template<typename T>
void foo ()
{
T::x();
}
int main ()
{
}
可以编译,即使我们知道在整个程序中C++没有一个函数名称x()
。仅当您尝试实例化foo<T>
时,编译器才会给出错误。
此外,如果您通过将main()
放在两个专业之间来稍微扭曲您的示例,它将编译得很好。
- .cpp和.h文件中的模板专用化声明
- 访问者访问变体并返回不同类型时出错
- 在Linux for Windows上编译C++代码时出错
- 读取文件的最后一行并输入到链接列表时出错
- 重载操作程序时出错>>用于类中的字符串 memebr
- 调用专用模板时出错"no matching function for call to [...]"
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- 模板专用化(按容器):value_type
- LINK 尝试使用 OpenSSL evp aes 256 c++ 时出错
- 在Google Kick start中提交时出错
- 在c++中访问int到类对象的映射时出错
- 分段错误当我试图运行程序时出错
- 使用dynamic_cast和构造函数时出错
- CHECK(调用)函数在Google Colab中出错
- 用pybind11包装C++抽象类时出错
- 为x86而非x64编译时出错
- 从R调用C++函数并对其进行集成时出错
- 类和成员函数模板专用化出错
- 树类的节点出错,可能是因为专用节点成员
- 为什么编译器在定义类似的模板专用化时不会出错?