Reputation: 2827
I doubt if gcc 4.8.3 inlines incorrect template functions... This problem does not occur in debug mode, but only in optimized mode. However this happens in a complicated code base, I am not able to reproduce the issue in a simple test case.
My code is like the following
#include "stdio.h"
class A {
public:
template<typename T> int WriteNative(const T) {
printf("here?\n")
return 0;
}
template<typename D>
void doit() {
if (WriteNative<double>(1)) {
printf("A\n");
} else {
printf("B\n");
}
}
};
// in my real code, this definition is in a different cpp file
template<> int A::WriteNative<double>(const double) {
return 1;
}
int main() {
A a;
a.doit<float>();
}
In debug build, it prints out A, while in optimized build, it prints out here?\nB
I guess any inliner uses the generic template function definition but not the specialized one. But attribute ((noinline)) does not help.
Does anyone if my code has a defined behavior of C++? and how to fix this issue?
Upvotes: 0
Views: 644
Reputation: 1725
You don't state this explicitly, but I'd guess in your actual code you were failing to declare the specialization in A
's .h file. So when A.h
was included in a separate compilation unit, the compiler was unaware of the specializatoin of WriteNative()
. Adding a declaration of the specialization should fix the issue without having to include the definition in the same file (i.e., not having to inline it):
class A {
public:
template<typename T> int WriteNative(const T) {
printf("here?\n")
return 0;
}
template<typename D>
void doit() {
if (WriteNative<double>(1)) {
printf("A\n");
} else {
printf("B\n");
}
}
};
template<> int A::WriteNative(const double);
You can reproduce your issue by using three files A.h
, A.cpp
, and main.cpp
, where A.cpp
contains the definition of the specialization, so that when main.cpp
includes A.h
, it is unaware of the specialization when inlining happens during optimization, and when compiled with -O0
, no inlining occurs, so WriteNative()
gets linked against the definition in A.cpp
.
Edit: See this answer which cites the spec to explain why this is correct behavior.
14.7.3 [temp.expl.spec]:
6/ If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined.
Upvotes: 2