Why does explicit template instantiation not break ODR?










3














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.










share|improve this question























  • AFAIK, there’s no difference between implicit and explicit instantiation other than the invisibility of the former.
    – molbdnilo
    Oct 5 at 11:20







  • 1




    Yeah, template instantiations are weak symbols, so the linker just chooses any which it feels like. Not too sure about it though, hence not an answer.
    – Hugo Maxwell
    Oct 5 at 11:30










  • @molbdnilo Thanks for the comment. I understand what you mean, but I'm not convinced why it should be like that. I have added a (convoluted) case where explicit initialization produces an unexpected result.
    – jdehesa
    Oct 5 at 11:41






  • 3




    "Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required."
    – geza
    Oct 5 at 11:42






  • 1




    strong/weak symbol are outside of c++ standard. it has been done to not force compiler to check that, IMO, as in general case it might be complicated to check each ODR violation.
    – Jarod42
    Oct 5 at 12:04
















3














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.










share|improve this question























  • AFAIK, there’s no difference between implicit and explicit instantiation other than the invisibility of the former.
    – molbdnilo
    Oct 5 at 11:20







  • 1




    Yeah, template instantiations are weak symbols, so the linker just chooses any which it feels like. Not too sure about it though, hence not an answer.
    – Hugo Maxwell
    Oct 5 at 11:30










  • @molbdnilo Thanks for the comment. I understand what you mean, but I'm not convinced why it should be like that. I have added a (convoluted) case where explicit initialization produces an unexpected result.
    – jdehesa
    Oct 5 at 11:41






  • 3




    "Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required."
    – geza
    Oct 5 at 11:42






  • 1




    strong/weak symbol are outside of c++ standard. it has been done to not force compiler to check that, IMO, as in general case it might be complicated to check each ODR violation.
    – Jarod42
    Oct 5 at 12:04














3












3








3







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.










share|improve this question















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.







c++ one-definition-rule explicit-instantiation






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 5 at 11:37

























asked Oct 5 at 11:03









jdehesa

22.2k43150




22.2k43150











  • AFAIK, there’s no difference between implicit and explicit instantiation other than the invisibility of the former.
    – molbdnilo
    Oct 5 at 11:20







  • 1




    Yeah, template instantiations are weak symbols, so the linker just chooses any which it feels like. Not too sure about it though, hence not an answer.
    – Hugo Maxwell
    Oct 5 at 11:30










  • @molbdnilo Thanks for the comment. I understand what you mean, but I'm not convinced why it should be like that. I have added a (convoluted) case where explicit initialization produces an unexpected result.
    – jdehesa
    Oct 5 at 11:41






  • 3




    "Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required."
    – geza
    Oct 5 at 11:42






  • 1




    strong/weak symbol are outside of c++ standard. it has been done to not force compiler to check that, IMO, as in general case it might be complicated to check each ODR violation.
    – Jarod42
    Oct 5 at 12:04

















  • AFAIK, there’s no difference between implicit and explicit instantiation other than the invisibility of the former.
    – molbdnilo
    Oct 5 at 11:20







  • 1




    Yeah, template instantiations are weak symbols, so the linker just chooses any which it feels like. Not too sure about it though, hence not an answer.
    – Hugo Maxwell
    Oct 5 at 11:30










  • @molbdnilo Thanks for the comment. I understand what you mean, but I'm not convinced why it should be like that. I have added a (convoluted) case where explicit initialization produces an unexpected result.
    – jdehesa
    Oct 5 at 11:41






  • 3




    "Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required."
    – geza
    Oct 5 at 11:42






  • 1




    strong/weak symbol are outside of c++ standard. it has been done to not force compiler to check that, IMO, as in general case it might be complicated to check each ODR violation.
    – Jarod42
    Oct 5 at 12:04
















AFAIK, there’s no difference between implicit and explicit instantiation other than the invisibility of the former.
– molbdnilo
Oct 5 at 11:20





AFAIK, there’s no difference between implicit and explicit instantiation other than the invisibility of the former.
– molbdnilo
Oct 5 at 11:20





1




1




Yeah, template instantiations are weak symbols, so the linker just chooses any which it feels like. Not too sure about it though, hence not an answer.
– Hugo Maxwell
Oct 5 at 11:30




Yeah, template instantiations are weak symbols, so the linker just chooses any which it feels like. Not too sure about it though, hence not an answer.
– Hugo Maxwell
Oct 5 at 11:30












@molbdnilo Thanks for the comment. I understand what you mean, but I'm not convinced why it should be like that. I have added a (convoluted) case where explicit initialization produces an unexpected result.
– jdehesa
Oct 5 at 11:41




@molbdnilo Thanks for the comment. I understand what you mean, but I'm not convinced why it should be like that. I have added a (convoluted) case where explicit initialization produces an unexpected result.
– jdehesa
Oct 5 at 11:41




3




3




"Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required."
– geza
Oct 5 at 11:42




"Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required."
– geza
Oct 5 at 11:42




1




1




strong/weak symbol are outside of c++ standard. it has been done to not force compiler to check that, IMO, as in general case it might be complicated to check each ODR violation.
– Jarod42
Oct 5 at 12:04





strong/weak symbol are outside of c++ standard. it has been done to not force compiler to check that, IMO, as in general case it might be complicated to check each ODR violation.
– Jarod42
Oct 5 at 12:04













2 Answers
2






active

oldest

votes


















2














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)






share|improve this answer




















  • Great work, that makes it quite clear indeed. I suppose it is more difficult than it seems for a compiler to diagnose this mistake. Btw, I think this implies that the compilation error for the third example in the question (with template specializations) is not actually guaranteed by the standard?
    – jdehesa
    Oct 5 at 16:05










  • @jdehesa In the third case, you declare explicit template specializations, this is treated in an other paragraph temp.expl.spec. (I was just reading it now), => no diagnostic required
    – Oliv
    Oct 5 at 16:11










  • @jdehesa But good news if you compile with gcc or clang, the symbol in the object file is not weak! So you will always get a link time error.
    – Oliv
    Oct 5 at 16:15










  • Oh I see, thanks, I thought that was covered by 5.2 in the paragraph you posted, and that the paragraph you linked was about the declaration-use order of the specialization. Anyway, NDR in any case! Thanks for checking with gcc and clang, I tested with MSVC and it seems to do the same.
    – jdehesa
    Oct 5 at 16:16










  • @jdehesa Indeed the second sentence of this last paragraph is redundant with the second bullet of the first paragraph.
    – Oliv
    Oct 5 at 16:22


















0














Both, explicit specialization and explicit instantiation definition will violate ODR based on the context they are used and the meaning of the entities they generate.



The following explain the first and the third case and why they does violate ODR with NDR [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 (according to 6.2), [...]




function templates may have different points of instantiation in both the same translation unit where they are defined and in others translation units, these specialization are guaranteed not to violate ODR when the meaning of these specialization is the same in all the points of instantiation.



since by [temp.point]/6




An explicit instantiation definition is an instantiation point for the specialization or specializations specified by the explicit instantiation.




and [temp.point]/8




[...] If two different points of instantiation give a template specialization different meanings according to the one-definition rule (6.2), the program is ill-formed, no diagnostic required.




the second case does not violate ODR, because the meaning of the instantiations in these TU is the same.



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


But the last is certainly not a valid one (violate ODR NDR), because even the function templates have the same signatures the instantiations from them will have different meanings. You can't relay in the result you got, the standard don't guarantee the behavior when these violation happens.



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





share|improve this answer






















  • Thank you for the detailed explanation, reading the standard can make me feel like Groucho Marx, but this is helpful. You explain that the first and third examples violate ODR with NDR, although these two are actually the ones where I get compilation errors. You mean then these compilation errors are not guaranteed by the standard, right?
    – jdehesa
    Oct 5 at 19:01










  • in the same section of [temp.spec]/5 state that the implementation is not required to diagnose, that make me think that no, they aren't obligated but these cases are IMO easy to recognize then, why not diagnose them?
    – Jans
    Oct 5 at 19:21










  • Aff... The second case is not valid, because it violates temp.spec/5.1 it can't be clearer. In the last one, ODR violation is due to the different template definitions see [basic.def.odr]/12, even without any template instantiation!
    – Oliv
    Oct 5 at 20:49










  • Last but not least, the point of instantiation can only change the definition of a template function because of dependent name lookup. There are no dependent name lookup in any definitions of template getNum. So your answer is realy out of the subject. Sorry!
    – Oliv
    Oct 5 at 21:08










  • @Oliv, for the second case (5.1) relate to appearing at most once(which it doesn't, NDR) but what is not clear to me is that is explicitly state that they constitue a ODR violation, because [basic.def.odr]/12 refer to template specialization for which some template parameters are not specified (which they aren't).
    – Jans
    Oct 5 at 21:59










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52664184%2fwhy-does-explicit-template-instantiation-not-break-odr%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









2














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)






share|improve this answer




















  • Great work, that makes it quite clear indeed. I suppose it is more difficult than it seems for a compiler to diagnose this mistake. Btw, I think this implies that the compilation error for the third example in the question (with template specializations) is not actually guaranteed by the standard?
    – jdehesa
    Oct 5 at 16:05










  • @jdehesa In the third case, you declare explicit template specializations, this is treated in an other paragraph temp.expl.spec. (I was just reading it now), => no diagnostic required
    – Oliv
    Oct 5 at 16:11










  • @jdehesa But good news if you compile with gcc or clang, the symbol in the object file is not weak! So you will always get a link time error.
    – Oliv
    Oct 5 at 16:15










  • Oh I see, thanks, I thought that was covered by 5.2 in the paragraph you posted, and that the paragraph you linked was about the declaration-use order of the specialization. Anyway, NDR in any case! Thanks for checking with gcc and clang, I tested with MSVC and it seems to do the same.
    – jdehesa
    Oct 5 at 16:16










  • @jdehesa Indeed the second sentence of this last paragraph is redundant with the second bullet of the first paragraph.
    – Oliv
    Oct 5 at 16:22















2














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)






share|improve this answer




















  • Great work, that makes it quite clear indeed. I suppose it is more difficult than it seems for a compiler to diagnose this mistake. Btw, I think this implies that the compilation error for the third example in the question (with template specializations) is not actually guaranteed by the standard?
    – jdehesa
    Oct 5 at 16:05










  • @jdehesa In the third case, you declare explicit template specializations, this is treated in an other paragraph temp.expl.spec. (I was just reading it now), => no diagnostic required
    – Oliv
    Oct 5 at 16:11










  • @jdehesa But good news if you compile with gcc or clang, the symbol in the object file is not weak! So you will always get a link time error.
    – Oliv
    Oct 5 at 16:15










  • Oh I see, thanks, I thought that was covered by 5.2 in the paragraph you posted, and that the paragraph you linked was about the declaration-use order of the specialization. Anyway, NDR in any case! Thanks for checking with gcc and clang, I tested with MSVC and it seems to do the same.
    – jdehesa
    Oct 5 at 16:16










  • @jdehesa Indeed the second sentence of this last paragraph is redundant with the second bullet of the first paragraph.
    – Oliv
    Oct 5 at 16:22













2












2








2






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)






share|improve this 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)







share|improve this answer












share|improve this answer



share|improve this answer










answered Oct 5 at 15:53









Oliv

8,2451955




8,2451955











  • Great work, that makes it quite clear indeed. I suppose it is more difficult than it seems for a compiler to diagnose this mistake. Btw, I think this implies that the compilation error for the third example in the question (with template specializations) is not actually guaranteed by the standard?
    – jdehesa
    Oct 5 at 16:05










  • @jdehesa In the third case, you declare explicit template specializations, this is treated in an other paragraph temp.expl.spec. (I was just reading it now), => no diagnostic required
    – Oliv
    Oct 5 at 16:11










  • @jdehesa But good news if you compile with gcc or clang, the symbol in the object file is not weak! So you will always get a link time error.
    – Oliv
    Oct 5 at 16:15










  • Oh I see, thanks, I thought that was covered by 5.2 in the paragraph you posted, and that the paragraph you linked was about the declaration-use order of the specialization. Anyway, NDR in any case! Thanks for checking with gcc and clang, I tested with MSVC and it seems to do the same.
    – jdehesa
    Oct 5 at 16:16










  • @jdehesa Indeed the second sentence of this last paragraph is redundant with the second bullet of the first paragraph.
    – Oliv
    Oct 5 at 16:22
















  • Great work, that makes it quite clear indeed. I suppose it is more difficult than it seems for a compiler to diagnose this mistake. Btw, I think this implies that the compilation error for the third example in the question (with template specializations) is not actually guaranteed by the standard?
    – jdehesa
    Oct 5 at 16:05










  • @jdehesa In the third case, you declare explicit template specializations, this is treated in an other paragraph temp.expl.spec. (I was just reading it now), => no diagnostic required
    – Oliv
    Oct 5 at 16:11










  • @jdehesa But good news if you compile with gcc or clang, the symbol in the object file is not weak! So you will always get a link time error.
    – Oliv
    Oct 5 at 16:15










  • Oh I see, thanks, I thought that was covered by 5.2 in the paragraph you posted, and that the paragraph you linked was about the declaration-use order of the specialization. Anyway, NDR in any case! Thanks for checking with gcc and clang, I tested with MSVC and it seems to do the same.
    – jdehesa
    Oct 5 at 16:16










  • @jdehesa Indeed the second sentence of this last paragraph is redundant with the second bullet of the first paragraph.
    – Oliv
    Oct 5 at 16:22















Great work, that makes it quite clear indeed. I suppose it is more difficult than it seems for a compiler to diagnose this mistake. Btw, I think this implies that the compilation error for the third example in the question (with template specializations) is not actually guaranteed by the standard?
– jdehesa
Oct 5 at 16:05




Great work, that makes it quite clear indeed. I suppose it is more difficult than it seems for a compiler to diagnose this mistake. Btw, I think this implies that the compilation error for the third example in the question (with template specializations) is not actually guaranteed by the standard?
– jdehesa
Oct 5 at 16:05












@jdehesa In the third case, you declare explicit template specializations, this is treated in an other paragraph temp.expl.spec. (I was just reading it now), => no diagnostic required
– Oliv
Oct 5 at 16:11




@jdehesa In the third case, you declare explicit template specializations, this is treated in an other paragraph temp.expl.spec. (I was just reading it now), => no diagnostic required
– Oliv
Oct 5 at 16:11












@jdehesa But good news if you compile with gcc or clang, the symbol in the object file is not weak! So you will always get a link time error.
– Oliv
Oct 5 at 16:15




@jdehesa But good news if you compile with gcc or clang, the symbol in the object file is not weak! So you will always get a link time error.
– Oliv
Oct 5 at 16:15












Oh I see, thanks, I thought that was covered by 5.2 in the paragraph you posted, and that the paragraph you linked was about the declaration-use order of the specialization. Anyway, NDR in any case! Thanks for checking with gcc and clang, I tested with MSVC and it seems to do the same.
– jdehesa
Oct 5 at 16:16




Oh I see, thanks, I thought that was covered by 5.2 in the paragraph you posted, and that the paragraph you linked was about the declaration-use order of the specialization. Anyway, NDR in any case! Thanks for checking with gcc and clang, I tested with MSVC and it seems to do the same.
– jdehesa
Oct 5 at 16:16












@jdehesa Indeed the second sentence of this last paragraph is redundant with the second bullet of the first paragraph.
– Oliv
Oct 5 at 16:22




@jdehesa Indeed the second sentence of this last paragraph is redundant with the second bullet of the first paragraph.
– Oliv
Oct 5 at 16:22













0














Both, explicit specialization and explicit instantiation definition will violate ODR based on the context they are used and the meaning of the entities they generate.



The following explain the first and the third case and why they does violate ODR with NDR [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 (according to 6.2), [...]




function templates may have different points of instantiation in both the same translation unit where they are defined and in others translation units, these specialization are guaranteed not to violate ODR when the meaning of these specialization is the same in all the points of instantiation.



since by [temp.point]/6




An explicit instantiation definition is an instantiation point for the specialization or specializations specified by the explicit instantiation.




and [temp.point]/8




[...] If two different points of instantiation give a template specialization different meanings according to the one-definition rule (6.2), the program is ill-formed, no diagnostic required.




the second case does not violate ODR, because the meaning of the instantiations in these TU is the same.



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


But the last is certainly not a valid one (violate ODR NDR), because even the function templates have the same signatures the instantiations from them will have different meanings. You can't relay in the result you got, the standard don't guarantee the behavior when these violation happens.



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





share|improve this answer






















  • Thank you for the detailed explanation, reading the standard can make me feel like Groucho Marx, but this is helpful. You explain that the first and third examples violate ODR with NDR, although these two are actually the ones where I get compilation errors. You mean then these compilation errors are not guaranteed by the standard, right?
    – jdehesa
    Oct 5 at 19:01










  • in the same section of [temp.spec]/5 state that the implementation is not required to diagnose, that make me think that no, they aren't obligated but these cases are IMO easy to recognize then, why not diagnose them?
    – Jans
    Oct 5 at 19:21










  • Aff... The second case is not valid, because it violates temp.spec/5.1 it can't be clearer. In the last one, ODR violation is due to the different template definitions see [basic.def.odr]/12, even without any template instantiation!
    – Oliv
    Oct 5 at 20:49










  • Last but not least, the point of instantiation can only change the definition of a template function because of dependent name lookup. There are no dependent name lookup in any definitions of template getNum. So your answer is realy out of the subject. Sorry!
    – Oliv
    Oct 5 at 21:08










  • @Oliv, for the second case (5.1) relate to appearing at most once(which it doesn't, NDR) but what is not clear to me is that is explicitly state that they constitue a ODR violation, because [basic.def.odr]/12 refer to template specialization for which some template parameters are not specified (which they aren't).
    – Jans
    Oct 5 at 21:59















0














Both, explicit specialization and explicit instantiation definition will violate ODR based on the context they are used and the meaning of the entities they generate.



The following explain the first and the third case and why they does violate ODR with NDR [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 (according to 6.2), [...]




function templates may have different points of instantiation in both the same translation unit where they are defined and in others translation units, these specialization are guaranteed not to violate ODR when the meaning of these specialization is the same in all the points of instantiation.



since by [temp.point]/6




An explicit instantiation definition is an instantiation point for the specialization or specializations specified by the explicit instantiation.




and [temp.point]/8




[...] If two different points of instantiation give a template specialization different meanings according to the one-definition rule (6.2), the program is ill-formed, no diagnostic required.




the second case does not violate ODR, because the meaning of the instantiations in these TU is the same.



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


But the last is certainly not a valid one (violate ODR NDR), because even the function templates have the same signatures the instantiations from them will have different meanings. You can't relay in the result you got, the standard don't guarantee the behavior when these violation happens.



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





share|improve this answer






















  • Thank you for the detailed explanation, reading the standard can make me feel like Groucho Marx, but this is helpful. You explain that the first and third examples violate ODR with NDR, although these two are actually the ones where I get compilation errors. You mean then these compilation errors are not guaranteed by the standard, right?
    – jdehesa
    Oct 5 at 19:01










  • in the same section of [temp.spec]/5 state that the implementation is not required to diagnose, that make me think that no, they aren't obligated but these cases are IMO easy to recognize then, why not diagnose them?
    – Jans
    Oct 5 at 19:21










  • Aff... The second case is not valid, because it violates temp.spec/5.1 it can't be clearer. In the last one, ODR violation is due to the different template definitions see [basic.def.odr]/12, even without any template instantiation!
    – Oliv
    Oct 5 at 20:49










  • Last but not least, the point of instantiation can only change the definition of a template function because of dependent name lookup. There are no dependent name lookup in any definitions of template getNum. So your answer is realy out of the subject. Sorry!
    – Oliv
    Oct 5 at 21:08










  • @Oliv, for the second case (5.1) relate to appearing at most once(which it doesn't, NDR) but what is not clear to me is that is explicitly state that they constitue a ODR violation, because [basic.def.odr]/12 refer to template specialization for which some template parameters are not specified (which they aren't).
    – Jans
    Oct 5 at 21:59













0












0








0






Both, explicit specialization and explicit instantiation definition will violate ODR based on the context they are used and the meaning of the entities they generate.



The following explain the first and the third case and why they does violate ODR with NDR [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 (according to 6.2), [...]




function templates may have different points of instantiation in both the same translation unit where they are defined and in others translation units, these specialization are guaranteed not to violate ODR when the meaning of these specialization is the same in all the points of instantiation.



since by [temp.point]/6




An explicit instantiation definition is an instantiation point for the specialization or specializations specified by the explicit instantiation.




and [temp.point]/8




[...] If two different points of instantiation give a template specialization different meanings according to the one-definition rule (6.2), the program is ill-formed, no diagnostic required.




the second case does not violate ODR, because the meaning of the instantiations in these TU is the same.



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


But the last is certainly not a valid one (violate ODR NDR), because even the function templates have the same signatures the instantiations from them will have different meanings. You can't relay in the result you got, the standard don't guarantee the behavior when these violation happens.



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





share|improve this answer














Both, explicit specialization and explicit instantiation definition will violate ODR based on the context they are used and the meaning of the entities they generate.



The following explain the first and the third case and why they does violate ODR with NDR [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 (according to 6.2), [...]




function templates may have different points of instantiation in both the same translation unit where they are defined and in others translation units, these specialization are guaranteed not to violate ODR when the meaning of these specialization is the same in all the points of instantiation.



since by [temp.point]/6




An explicit instantiation definition is an instantiation point for the specialization or specializations specified by the explicit instantiation.




and [temp.point]/8




[...] If two different points of instantiation give a template specialization different meanings according to the one-definition rule (6.2), the program is ill-formed, no diagnostic required.




the second case does not violate ODR, because the meaning of the instantiations in these TU is the same.



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


But the last is certainly not a valid one (violate ODR NDR), because even the function templates have the same signatures the instantiations from them will have different meanings. You can't relay in the result you got, the standard don't guarantee the behavior when these violation happens.



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






share|improve this answer














share|improve this answer



share|improve this answer








edited Oct 5 at 22:05

























answered Oct 5 at 17:19









Jans

7,63422334




7,63422334











  • Thank you for the detailed explanation, reading the standard can make me feel like Groucho Marx, but this is helpful. You explain that the first and third examples violate ODR with NDR, although these two are actually the ones where I get compilation errors. You mean then these compilation errors are not guaranteed by the standard, right?
    – jdehesa
    Oct 5 at 19:01










  • in the same section of [temp.spec]/5 state that the implementation is not required to diagnose, that make me think that no, they aren't obligated but these cases are IMO easy to recognize then, why not diagnose them?
    – Jans
    Oct 5 at 19:21










  • Aff... The second case is not valid, because it violates temp.spec/5.1 it can't be clearer. In the last one, ODR violation is due to the different template definitions see [basic.def.odr]/12, even without any template instantiation!
    – Oliv
    Oct 5 at 20:49










  • Last but not least, the point of instantiation can only change the definition of a template function because of dependent name lookup. There are no dependent name lookup in any definitions of template getNum. So your answer is realy out of the subject. Sorry!
    – Oliv
    Oct 5 at 21:08










  • @Oliv, for the second case (5.1) relate to appearing at most once(which it doesn't, NDR) but what is not clear to me is that is explicitly state that they constitue a ODR violation, because [basic.def.odr]/12 refer to template specialization for which some template parameters are not specified (which they aren't).
    – Jans
    Oct 5 at 21:59
















  • Thank you for the detailed explanation, reading the standard can make me feel like Groucho Marx, but this is helpful. You explain that the first and third examples violate ODR with NDR, although these two are actually the ones where I get compilation errors. You mean then these compilation errors are not guaranteed by the standard, right?
    – jdehesa
    Oct 5 at 19:01










  • in the same section of [temp.spec]/5 state that the implementation is not required to diagnose, that make me think that no, they aren't obligated but these cases are IMO easy to recognize then, why not diagnose them?
    – Jans
    Oct 5 at 19:21










  • Aff... The second case is not valid, because it violates temp.spec/5.1 it can't be clearer. In the last one, ODR violation is due to the different template definitions see [basic.def.odr]/12, even without any template instantiation!
    – Oliv
    Oct 5 at 20:49










  • Last but not least, the point of instantiation can only change the definition of a template function because of dependent name lookup. There are no dependent name lookup in any definitions of template getNum. So your answer is realy out of the subject. Sorry!
    – Oliv
    Oct 5 at 21:08










  • @Oliv, for the second case (5.1) relate to appearing at most once(which it doesn't, NDR) but what is not clear to me is that is explicitly state that they constitue a ODR violation, because [basic.def.odr]/12 refer to template specialization for which some template parameters are not specified (which they aren't).
    – Jans
    Oct 5 at 21:59















Thank you for the detailed explanation, reading the standard can make me feel like Groucho Marx, but this is helpful. You explain that the first and third examples violate ODR with NDR, although these two are actually the ones where I get compilation errors. You mean then these compilation errors are not guaranteed by the standard, right?
– jdehesa
Oct 5 at 19:01




Thank you for the detailed explanation, reading the standard can make me feel like Groucho Marx, but this is helpful. You explain that the first and third examples violate ODR with NDR, although these two are actually the ones where I get compilation errors. You mean then these compilation errors are not guaranteed by the standard, right?
– jdehesa
Oct 5 at 19:01












in the same section of [temp.spec]/5 state that the implementation is not required to diagnose, that make me think that no, they aren't obligated but these cases are IMO easy to recognize then, why not diagnose them?
– Jans
Oct 5 at 19:21




in the same section of [temp.spec]/5 state that the implementation is not required to diagnose, that make me think that no, they aren't obligated but these cases are IMO easy to recognize then, why not diagnose them?
– Jans
Oct 5 at 19:21












Aff... The second case is not valid, because it violates temp.spec/5.1 it can't be clearer. In the last one, ODR violation is due to the different template definitions see [basic.def.odr]/12, even without any template instantiation!
– Oliv
Oct 5 at 20:49




Aff... The second case is not valid, because it violates temp.spec/5.1 it can't be clearer. In the last one, ODR violation is due to the different template definitions see [basic.def.odr]/12, even without any template instantiation!
– Oliv
Oct 5 at 20:49












Last but not least, the point of instantiation can only change the definition of a template function because of dependent name lookup. There are no dependent name lookup in any definitions of template getNum. So your answer is realy out of the subject. Sorry!
– Oliv
Oct 5 at 21:08




Last but not least, the point of instantiation can only change the definition of a template function because of dependent name lookup. There are no dependent name lookup in any definitions of template getNum. So your answer is realy out of the subject. Sorry!
– Oliv
Oct 5 at 21:08












@Oliv, for the second case (5.1) relate to appearing at most once(which it doesn't, NDR) but what is not clear to me is that is explicitly state that they constitue a ODR violation, because [basic.def.odr]/12 refer to template specialization for which some template parameters are not specified (which they aren't).
– Jans
Oct 5 at 21:59




@Oliv, for the second case (5.1) relate to appearing at most once(which it doesn't, NDR) but what is not clear to me is that is explicitly state that they constitue a ODR violation, because [basic.def.odr]/12 refer to template specialization for which some template parameters are not specified (which they aren't).
– Jans
Oct 5 at 21:59

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52664184%2fwhy-does-explicit-template-instantiation-not-break-odr%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)