Declare function template instantiation without the template - c++

Is it possible to declare that a symbol is an explicit instantiation of a function template, without defining the function template first?
It would express to the compiler that there exists a function template in another translation unit that is instantiated somewhere, and we want to call the instantiated function.
// declaration of instantiation, perhaps it would look like one of these:
// template<typename> void foo(int);
// template<typename> void foo<int>(int);
void bar(int i) {
// definition of function unknown to caller, it shouldn't matter
foo(i);
// either that or this perhaps:
foo<int>(i);
}
Is there a technical reason this can't be done or is it just for lack of syntax? Is there a reason that it's not possible to provide sufficient information in a declaration to generate calls to an instantiated function template?
There is no Y behind this X. This question is meant literally. It's an abstract question about the C++ language. I could provide an example that doesn't compile but that would just be a distraction.
The question is also not about specialization per se. Whether the template was specialized shouldn't matter. This question is only concerned with declaring that a template exists and that it was instantiated.
Related question: How do I explicitly instantiate a template function? - however that does not solve this problem, as it requires the full template definition to be visible.

You can use "extern template" here. It tells the compiler not to instantiate it in every translation units. This is part of C++11 enhancements. For example, we may declare the template in a header file a.hpp as
// a.hpp
template <class T>
T fun(T& a);
Then in a.cpp
// a.cpp
#include "a.hpp"
extern template int fun(int&);
int main()
{
int a = 100;
return fun(100);
}
And in b.cpp we can actually instantiate the template:
// b.cpp
#include "a.hpp"
template <>
int fun(int& x)
{
return x + 1;
}

To add to Nipun Talukdar's answer, there's no need for specialization or for the template definition to be visible to the caller.
a.cpp
template<class T> T fun(T);
extern template int fun(int);
int main() {
// this works, even though we have no idea how fun() is defined
fun(100);
// this would fail to link
// fun('a');
}
b.cpp
template<class T>
T fun(T x) {
return x;
}
// explicit instantiation
template int fun<int>(int x);

Related

C++: Is there any sense using the "extern" keyword for templates?

Consider the following example:
fnc.h:
#include <iostream>
template <class T> //common template definition
void fnc()
{
std::cout << "common";
}
fnc.cpp:
#include "fnc.h"
template<> //specialization for "int"
void fnc<int>()
{
std::cout << "int";
}
main.cpp
#include "fnc.h"
extern template void fnc<int>(); // compiler will not generate fnc<int> and linker will be used to find "fnc<int>" in other object files
int main()
{
fnc<double>(); //using instantiation from common template
fnc<int>(); using specialization from "fnc.cpp"
}
Then I replace extern template void fnc<int>(); with template<> void fnc<int>(); and assume the behavior will be same. Is there any real meaning to using the extern keyword with templates or was it introduced for readability only?
It's not for specializations. Technically what you did is ill-formed, no diagnostic required. You have an explicit instantiation declaration, but no matching definition. The explicit specialization doesn't count for matching against the declaration you provided (even though some compilers implement it in a way that hides the fact).
This construct is for deferring instantiation, to make a compiler not try to instantiate the template in the current translation unit. So you may use it for hiding the template completely and exposing only for a finite set of types:
Header:
template <class T>
void fnc();
extern template void fnc<int>(); // The instantiation is elsewhere.
Source:
template <class T> //common template definition
void fnc()
{
std::cout << "common";
}
template void fnc<int>(); // explicit instantiation
Or to prevent a frequently used specialization from being instantiated in every TU:
Common header:
#include <vector>
extern template std::vector<unsigned char>; // look for member definitions elsewhere.
One source file:
template std::vector<unsigned char>; // The member functions are defined in this TU
The later use case may save a on compile times.

How can I turn on the auto matching when invoking the template explicit instantiation?

I have two template class, and the Leaf<T> is derived from the Base<T>, then I developed a template function which uses the reference of the Base<T> as its parameter. And set the definition and the instantiation of that function in its source file.
The issue happened once I tried to pass the Leaf<T> as the argument of that function. The compiler tries to find the symbol with Leaf<T> without the auto convention as it used to be.
// foo.h
#ifndef __FOO_H_INCLUDED__
#define __FOO_H_INCLUDED__
#include <base.h>
template <typename T>
void Foo(T &value);
#endif // __FOO_H_INCLUDED__
// foo.cpp
#include <foo.h>
#include <iostream>
template <typename T>
void Foo(T &value)
{
std::cout<<value.getValue()<<std::endl;
}
template void Foo(MyBase<int> &value);
// main.cpp
#include <leaf.h>
#include <foo.h>
int main()
{
int i = 20;
MyLeaf<int> leaf;
leaf.setValue(i);
Foo(leaf);
}
The above snippet will throw an "undefined reference" exception in linking. Refactor the invoking as Foo<MyBase<int> >(leaf) will fix the issue but that not what I want. And explicitly instantiate all of the potential derived types is also impossible because there is no way to know how many are them.
So is there a way that could make the linker recognize my symbols with the base type rather than find the precise one and throw an error?
Adding an explicit template instantiation in one translation unit must be paired with an explicit template instantiation declaration to make sure the compiler doesn't try to do an implicit instantiation. Otherwise, the program is ill-formed.
Beyond that, you can't have template argument deduction deduce anything other than Foo<MyLeaf<int>> the way you have it setup. But with a bit of tweaking, we can have it working. In your header:
template <typename T>
void Foo(MyBase<T> &value);
extern template void Foo(MyBase<int> &value);
And in your implementation file:
template <typename T>
void Foo(MyBase<T> &value)
{
std::cout<<value.getValue()<<std::endl;
}
template void Foo(MyBase<int> &value);
Now the deduction rules, and overload resolution should match the functions correctly. What we did is shift the burden. Now that function always expects a class instantiated from MyBase. And since every class instantiated from MyLeaf is also derived from one instantiated from MyBase, you see where it goes. We fulfill the templates requirement for the argument, and just leave it to deduce T from it.

gcc inline the generic template function with a specialized definition

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?
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.

The meaning of template keyword in the function declaration

What has the meaning the "using of template keyword in the function declaration"?
In this example compiler errors with error: "func" is not a template function.
template<typename T>
struct Window {
T value;
};
template void func(Window<int>, int);
template<typename T>
void func(Window<T>, T) {
}
int main(void) {
}
But below example is ok.
template<typename T>
struct Window {
T value;
};
template<typename T>
void func(Window<T>, T) {
}
template void func(Window<int>, int);
int main(void) {
}
What is the meaning with "template" in the above case?
Is it just indicator that this function is template function?
A declaration that begins with the keyword template and does not have the <pointy braces> immediately afterward is called an explicit instantiation. It means to look up the template definition and plug in the specified template parameters to get a specific function specialization or class specialization. So in the first example, the compiler is complaining it can't instantiate func(Window<int>, int) because it doesn't yet know anything about a template called func.
Explicit instantiations are usually not necessary, since templates can be implicitly instantiated just by attempting to use them. But explicit instantiation gives some control over where and how related linker symbols appear, and can in some cases be used to move a template definition out of a header file into a source file.
This is just because in your first example you have the definition of the template
template<typename T>
void func(Window<T>, T) {
}
after the forced instantiation that's represented by this line:
template void func(Window<int>, int);
Whereas in the second example they're the right way around.
But the comment to your question is fair, you are asking a basic question ('what does template mean'), which is best answered by a thoroughgoing study of the subject.

What's the right way to specialize a template when using "extern template"?

I am hoping someone can point out the correct way to specialize a method in a template class while using "extern template class" and "template class" for explicit instantiation with gnu c++. I've tried to boil down this problem with the simplest example that mimics my real problem. It appears that declaring "extern template" implies a template instantiation which causes errors when specializing methods. Given a driver program:
main.cc
#include A_H
#include <iostream>
int main()
{
A<int> ai;
A<long> al;
std::cout << "ai=" << ai.get() << " al=" << al.get() << std::endl;
return 0;
}
And the following implemntation of A
a.h
template<typename T>
struct A
{
int get() const;
};
extern template class A<int>;
extern template class A<long>;
a.cc
#include "a.h"
template<typename T>
int A<T>::get() const
{
return 0;
}
template<>
int A<long>::get() const
{
return 1;
}
template class A<int>;
template class A<long>;
I receive the following error when compiling with either, g++ 4.1.2 or 4.4.4
% g++ -Wall -g -D'A_H="a.h"' a.cc main.cc
a.cc:10: error: specialization of 'int A<T>::get() const [with T = long int]' after instantiation
%
If I comment out the two "extern template" lines in a.h, things compile and work as expected with both compilers. I assume depending on the existence of an explicit instantiation in the absence of "extern template" is unspecified behavior even in C++0x, otherwise, what's the point of C++0x adding "extern template"?
If I instead implement A as:
a-hack.h
template<typename T>
struct A
{
int get() const;
};
template<typename T>
int A<T>::get() const
{
return 0;
}
template<>
inline
int A<long>::get() const
{
return 1;
}
extern template class A<int>;
extern template class A<long>;
a-hack.cc
#include "a-hack.h"
template class A<int>;
template class A<long>;
and compile again, this works as expected
% g++ -Wall -g -D'A_H="a-hack.h"' a-hack.cc main.cc
% ./a.out
ai=0 al=1
However, in my real world example, this causes a program crash with g++ 4.1.2 (while working for g++ 4.4.4). I have not narrowed down the exact cause of the crash (segmentation fault). It only appears as if the stack pointer is corrupted within what would be the call to A<>::get().
I realize that explicit template instantiation is non-standard at this point, but would anyone expect what I've done above to work? If not, what is the correct way to do this?
Thanks
extern template class A<long>;
This line says that A<long> is to be explicitly instantiated according to the definitions the compiler has already seen. When you add a specialization later, you break that meaning.
Add a declaration of your specialization to the header file.
template <typename T> struct A { /*...*/ };
template<> int A<long>::get() const;
extern template class A<int>;
extern template class A<long>;
In general, it's best to put as many specialization declarations as possible in the same header file as the primary template, to reduce surprises for the compiler about which declaration should be used for any particular instantiation.
Notice that the extern template declaration isn't necessary if you're dealing with a single template entity (as opposed to this case, where we have to instruct the compiler about both the class A<long> and the function A<long>::get()). If you want to specialize a function template in another translation unit, it suffices to write just template<>.
template<typename T> int freeGet() { return 0; } // you can even add "inline" here safely!
template<> int freeGet<long>(); // this function is not inline (14.7.3/12)
But you must have the <> there. If you omit the <>, the declaration turns into an explicit instantiation of the default implementation (return 0), which is likely not what you wanted! Even if you add extern, the compiler is allowed to inline that default implementation; if your code unexpectedly breaks when you pass -O2, you might have accidentally omitted the <> somewhere.
Adding this answer to address the question in the title (template instantiation, and not necessarily template method instantiation).
This much resembles function declaration/definition.
Explicit instantiation declaration: extern template class is a declaration and should generally go in the header.
Explicit instantiation definition: template class is a definition and should generally go in the cpp.
No code is generated in object files following the declaration.
Code is generated in the object file of the cpp that contained the definition.
Without explicit instantiation, implicit instantiation will take place when the template is actually used. This will happen in every compilation unit (object file) that uses the template.
Implicit instantiation won't take place if a declaration was encountered. This is the gist of this mechanism - avoid object code duplication caused by implicit instantiation that happened because the compiler didn't trust that there's a single compilation unit in charge of instantiating the template.
More info here.