I need to be able to insert stub code into a template function, where the stub code is specialized. This is allowed by most compilers if I use a trampoline like
template <class T>
T foo(T t) {
if(Stub<T>::enabled) {
return Stub<T>::stub(t);
}
/* actual code here */
}
/* use of foo occurs here */
template <>
int Stub<int>::stub(int) { /* stub code */ }
At least this works for most versions of GCC, clang and MSVC. There are some older versions of GCC and GCC-derived compilers that do not accept this and complain that explicit specialization of Stub<T>::stub
cannot occur after its first use.
My question is -- is there a workaround for these compilers -- and if not, is this something that's allowed as far as the standard is concerned? Or am I relying on GCC/Clang/MSVC to all just "do the right thing"?
This is ODR issue. I think no diagnostic is required, but the code is ill formed nonetheless.
To fix this, you can declare the specialization before defining it:
template <class T>
T foo(T t) {
if(Stub<T>::enabled) {
return Stub<T>::stub(t);
}
/* actual code here */
}
/* declaration */
template <>
int Stub<int>::stub(int);
/* use of foo occurs here */
template <>
int Stub<int>::stub(int) { /* stub code */ }
Why I think it's an ODR issue.
Look at example1 and example2. Both use the template the same way. One is inlining the primary template and the other is calling the missing specialization, since the specialization might be in another translation unit somewhere.
Adding the specialization to another translation unit in exaxple 1 would be IFNDR, which can be really hard to debug.
In this use of the function foo
/* use of foo occurs here */
there is implicitly instantiated specialization Stub<int>::stub(int)
.
However the declaration of the specialization is provided after the instantiation
template <>
int Stub<int>::stub(int) { /* stub code */ }
The program is ill-formed. However the Standard does not require a compiler diagnostic.
From the C++ 17 Standard (17.8.3 Explicit specialization)
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.
What you need is to write the code such a way that it would satisfy the Standard. That is place the declaration of the explicit specialization before the implicit instantiation.
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