Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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

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

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).

EDIT:

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

Output:

1

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
292 views
Welcome To Ask or Share your Answers For Others

1 Answer

Eureka! I finally fall on the relevant paragraph, [temp.spec]/5

For a given template and a given set of template-arguments,

  • (5.1) an explicit instantiation definition shall appear at most once in a program,

  • (5.2) an explicit specialization shall be defined at most once in a program, as specified in [basic.def.odr], and

  • (5.3) both an explicit instantiation and a declaration of an explicit specialization shall not appear in a program unless the explicit instantiation follows a declaration of the explicit specialization.

An implementation is not required to diagnose a violation of this rule.

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)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share

548k questions

547k answers

4 comments

86.3k users

...