Reputation: 12567
I found an example where the output is different depending on the optimization settings (-O3
vs none), yet GCC 4.8.2 produces no warnings, even with the -std=c++11 -Wall -pedantic
options.
In this particular case, I'm assuming that "forgetting" the commented line in header.h
is a mistake, and with -O3
, c<int>::get()
gets inlined.
However, is there any way to protect yourself against these kinds of mistakes -- a compiler or linker option perhaps?
header.h:
#ifndef HEADER_H
#define HEADER_H
template<class T>
struct c
{
int get() { return 0; }
};
// template<> int c<int>::get();
#endif
imp.cpp:
#include "header.h"
template<>
int c<int>::get()
{
return 1;
}
main.cpp:
#include <iostream>
#include "header.h"
int main()
{
c<int> i;
std::cout << i.get() << '\n'; // prints 0 with -O3, and 1 without
}
build:
c++ -std=c++11 -pedantic -Wall -O3 -c imp.cpp
c++ -std=c++11 -pedantic -Wall -O3 -c main.cpp
c++ -std=c++11 -pedantic -Wall -O3 imp.o main.o
Upvotes: 3
Views: 189
Reputation: 45654
What you get if you have the line in your header-file, is a declaration of an explicit specialization for that member-function.
Thus, main.cpp is assured of a definition in some other compilation-unit, and things work.
If you leave it out, you have a violation of the ODR:
That specific instantiation of your class-template is different in the compilation-units. Resulting in "ill-formed, no diagnostic required", so anything goes.
And there is (currently?) no compiler-option to force gcc to diagnose it.
Upvotes: 6
Reputation: 249093
The true mistake here is the way you're laying out your source files and building them. When c<int>::get()
is used, its definition should be available in order to instantiate the template. To fix this, header.h
should #include "imp.cpp"
rather than the other way around. You may want to rename imp.cpp
to imp.inl
or something else.
When you define templates which are used outside of a single .cpp
file, those definitions should be visible to anyone who includes their header.
As an aside: I don't think there's any way to make the compiler or linker warn you about what you've done here. But if you structure your project as I've described, this problem won't happen, because the forward declaration will be unnecessary.
Upvotes: 0