问题描述
此问题是在此答案的背景下出现的.
This question arised in the context of this answer.
正如我期望的那样,此翻译单元无法编译:
As I would expect, this translation unit does not compile:
template <int Num> int getNum() { return Num; }
template int getNum<0>();
template int getNum<0>(); // error: duplicate explicit instantiation of 'getNum<0>'
int main() { getNum<0>(); return 0; }
我理解这一点,我试图两次进行相同的显式模板实例化.然而,事实证明,将其分为不同的单元,它会编译:
I understand this, I have tried to make the same explicit template instantiation twice. However, it turns out that, separating this into different units, it compiles:
// decl.h
template <int Num> int getNum() { return Num; }
// a.cc
#include <decl.h>
template int getNum<0>();
// b.cc
#include <decl.h>
template int getNum<0>();
int main() { getNum<0>(); return 0; }
我没想到这一点.我假设具有相同参数的多个显式模板实例化将破坏ODR,但事实并非如此.但是,这确实失败了:
I did not expect this. I assumed that multiple explicit template instantiations with the same parameters would break ODR, but that does not seem to be the case. This, however, does fail:
// decl.h
template <int Num> int getNum();
// a.cc
#include "decl.h"
template <> int getNum<0>() { return 0; }
// b.cc
#include "decl.h"
template <> int getNum<0>() { return 0; }
int main() { getNum<0>(); return 0; }
用户 Oliv 很有帮助地将我指向标准中的相关段落,但是我对此仍然有些困惑,因此我希望有人可以用更简单的术语来解释其背后的逻辑(例如,什么应该或不应该考虑破坏ODR以及为什么我的期望是错误的.)
User Oliv helpfully pointed me to this relevant paragraph in the standard, but I am still somewhat confused by it, so I was hoping someone could explain in simpler terms the logic behind this (as in, what should or should not be considered to break ODR and why my expectation was wrong).
再举一个例子,这是一个分为两个单元的程序,可以正确编译,但可以产生令人惊讶的结果:
As a further example, here is a program divided in two units that compiles correctly yet it produces arguably surprising results:
// a.cc
template <int Num> int getNum() { return Num + 1; }
template int getNum<0>();
// b.cc
#include <iostream>
template <int Num> int getNum() { return Num; }
template int getNum<0>();
int main() { std::cout << getNum<0>() << std::endl; return 0; }
输出:
1
在这种情况下,删除显式模板实例将生成0
.我知道拥有两个具有不同定义的模板不是一个常见的用例,但是我认为ODR的执行是为了避免此类问题.
In this case, removing the explicit template instantiations produces 0
. I know that having two templates with different definitions is not a common use case, but I thought ODR was precisely enforced to avoid this sort of problem.
推荐答案
尤里卡!我终于找到了相关的段落[temp.spec]/5
Eureka! I finally fall on the relevant paragraph, [temp.spec]/5
-
(5.1) 一个显式的实例化定义最多应在程序中出现一次,
(5.1) an explicit instantiation definition shall appear at most once in a program,
(5.2) 如[basic.def.odr]和
(5.2) an explicit specialization shall be defined at most once in a program, as specified in [basic.def.odr], and
不需要执行即可诊断是否违反了此规则.
An implementation is not required to diagnose a violation of this rule.
因此,显式模板实例化定义(而非隐式实例化)可能会导致违反ODR,不需要诊断(至少gcc和clang-ld工具链不会产生诊断)
So explicit template instantiation definition (not implicit instantiation) can cause ODR violation, no diagnostic required (and at least gcc and clang - ld toolchains do not produce diagnostic)
这篇关于为什么显式模板实例化不会破坏ODR?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!