Depending on whether I compile with -O3 or without optimization the compiler does not select the same function-template-instanciation. Using gcc (Debian 8.3.0-6) 8.3.0.
Due to an oversight I have a default implementation in a function template declaration:
#pragma once
#include <iostream>
template <int>
void func() { std::cerr << "default impl\n"; } // normally no impl here
And their specialisations:
#include "func.h"
template <>
void func<1>()
{
std::cerr << "special 1\n";
}
template <>
void func<2>()
{
std::cerr << "special 2\n";
}
And the main-function.
#include "func.h"
int main(void)
{
func<1>();
func<2>();
return 0;
}
Compiling and running g++ -Wall func.cpp main.cpp -o main && ./main
gives:
special 1
special 2
Using optimizations g++ -O3 -Wall func.cpp main.cpp -o main && ./main
gives:
default impl
default impl
Is this expected? Is the code triggering an unexpected behavior I'm not aware of?
Thanks to @NathanOliver from the comments who made a Wandbox. Compiling with or without optimizations shows the different output.
Your code is ill-formed, no diagnostic required. So different behaviors at different optimization levels are possible.
[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.
The function template is specialized in one TU, but the other doesn't have a specialization declaration available. It's quite likely an aggressive optimizer chooses the implicit instantiation (that is available inline) instead of finding the one you created elsewhere. The solution is to declare that your specialization exists in the header.
You have undefined behaviour because of ODR issues.
ODR says that there should be only one definition for each symbol. Inline and template functions can multiple definitions but must have the same implementation, token by token. No diagnostic required if this rule is broken.
When compiling your example, the compiler will instantiate your function. Look at this:
template <int>
void func() { std::cerr << "default impl\n"; } // normally no impl here
int main(void)
{
func<1>();
func<2>();
return 0;
}
This is what the compiler sees. It cannot see other cpp files. The compiler will instantiate the templates and create additional definition for your functions.
Then your other cpp file will provide another definition that is different.
The solution to this is to forward declare the specializations in your header:
template<> void func<1>();
template<> void func<2>();
This will tell the compiler that the specializations are declared elsewhere, and not to instantiate the default one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With