Why template functions do not show in the LLVM-IR if the function is not called, when emitting LLVM IR from a c++ code,
unlike other types of functions (int, float...) which will be present in the llvm ir
example: the following function func1 doesnt show in llvm ir
template <class tmp>
tmp func1 () {
// ...
}
But this function func2 always shows in llvm ir
int func2 () {
// ...
}
This is because your templates are not functions: they are function templates. They are not compiled until it is instantiated with arguments. For example, take this code:
template<typename T>
T foo() { /* ... */ }
That will nor output any code.
But this on the other hand:
template<typename T>
T foo() { /* ... */ }
int test() {
return foo<int>();
}
Will output the code for both test and foo<int>.
You can also manually instantiate a template like this:
template int foo<int>();
This has to do with how C++ templates work. Since the compiler doesn’t know what tmp is until you call the function (or more precisely, when you instantiate it), it doesn’t know how to write code for it. For example, consider this template:
template <typename T>
T add(T left, T right) {
return left + right;
}
If T is an integer, then the function body is an integer add. If T's a double, it’s a floating-point add. If T’s a std::string, it’s a function call to std::string::operator+.
Since there are a lot of types in any C++ program, and many of them can be added, and pretty much every one is added in different ways, it cannot create the code for the function until it knows this type. If it tried to do it for all possible types T, you’d get a combinatorial explosion of possible implementations, almost all of which are never used. Your compile time and binary size would be huge for little if any benefit.
Things get slightly more complicated with class templates. An instantiation of a class template doesn’t actually need to instantiate all the functions if they aren’t called. Going back to our example, if we instead wrote:
template <typename T>
class Adder {
T add(T left, T right) {
return left + right;
}
};
Adder<int> a;
this still wouldn’t instantiate Adder<int>::add even though the compiler has all the information to know that add<int> is potentially interesting, because you don’t actually call or otherwise instantiate it.
Related
Let's say I have a C++ class Foo. It has a templatized method setValue() that needs to accept any of the following as its argument:
Any primitive type
An object of type Bar
An object of a subclass of Bar
I want to write something like this.
template <class T>
void setValue(T& value) {
if (std::is_fundamental<T>::value)
setPrimitiveValue(value)
else {
Bar* bar = dynamic_cast<Bar*>(&value);
if (bar != NULL)
setBarValue(*bar);
}
}
But this doesn't compile. When I call the method with an int, the compiler complains that dynamic_cast can't be used on an int*. Even though that code branch doesn't get executed for primitives, the compiler still needs to compile it.
How can I make this work? Note this is a method in a class, so template specializations aren't allowed.
Since C++17 you can easily address this problem with if constexpr.
As you can expect, it can exclude an entire branch from the compilation (rather than the execution, as a normal if).
Note: the code is still subjected to syntax rules. Details are out of the scope of this answer.
template <class T>
void setValue(T& value) {
if constexpr (std::is_fundamental<T>::value)
setPrimitiveValue(value)
else {
Bar* bar = dynamic_cast<Bar*>(&value);
if (bar != NULL)
setBarValue(*bar);
}
}
The answer from Biagio Festa looks perfect as long as you can use C++17. I can't since I still need to support older compilers, but that answer led me to Constexpr if alternative which gives several alternatives. Here's the solution I ended up with which works even on C++11.
template <class T>
typename std::enable_if<std::is_fundamental<T>::value, void>::type setValue(T& value) {
setPrimitiveValue(value);
}
void setValue(Bar& value) {
setBarValue(value);
}
My problem could be described with the example below.
I want to call a static function from each instantiation of a template. What I am thinking of is something like a tuple which gets expanded each time a new instantiation of a template is encountered, so that I can access that tuple recursively and call a static function of each of the types in the tuple.
#include <vector>
template<typename T>
struct Junk
{
static std::vector<T> all;
Junk(T t)
{
all.push_back(t);
}
static void clear()
{
all.clear();
}
};
template<typename T>
std::vector<T> Junk<T>::all;
void clearJunk()
{
Junk<float>::clear();
Junk<char>::clear();
Junk<unsigned int>::clear();
// how can I generalize this?
}
int main()
{
// instantiate Junk with different types
Junk<float> f1(1.0f);
Junk<float> f2(2.0f);
// Junk<float>::all.size() == 2
Junk<char> c1('a');
Junk<char> c2('b');
Junk<char> c3('c');
// Junk<char>::all.size() == 3
Junk<unsigned int> i1(1);
// Junk<unsigned int>::all.size() == 1
// clear all Junk
clearJunk();
return 0;
}
A run-time solution to this would be a vector of function pointers, and the first object of each template instantiation pushes a pointer to the static member function to that vector:
std::vector<void(*)()> clear_funcs;
template<typename T>
struct Junk
{
static std::vector<T> all;
Junk(T t)
{
(void)init; // mention init at least once so its constructor will be invoked
all.push_back(t);
}
static void clear()
{
all.clear();
}
struct At_Init
{
At_Init()
{
clear_funcs.push_back(&Junk<T>::clear);
}
};
static At_Init init; // will only be constructed once for each template instantiation
};
template<typename T>
std::vector<T> Junk<T>::all;
template<typename T>
typename Junk<T>::At_Init Junk<T>::init;
void clearJunk()
{
// call every clear() of all the Junk template instantiations
for (void(*clear)() : clear_funcs) {
clear();
}
}
But this solution is not as fast as a compile time solution would be and it requires a lot of code in the class that is not at all meaningful, so I dislike this solution, although it works.
How could you generate code at compile-time to call a static function of every instantiation of a template?
You are out of luck.
To see why, imagine there are 3 dynamic libraries. They each use a Junk<typeX> where X is 0, 1 or 2.
These libraries are loaded after the program runs, depending on the phase of the moon.
No central location can possibly know which Junk<?>::clear() methods to invoke at compile time. In order to know which methods to invoke, you'd have to have a central location responsible for it and track at runtime which Junk<?> types are instantiated.
Now, you may not be using dynamic libraries, but the fact that the language (in practice) supports this means that there isn't a way to track cross compilation units an enumeration of all types instantiated from a template without storing it as runtime state. At compile time, each compilation unit (cpp file) can be compiled separately.
Naturally there are ways around this; if you had only one compilation unit (or even a unity build), or if you maintained a central list of types supported (and optionally generated hard compile time errors if you missed types), you could generate code like your static code case.
But before you do that, profile your simple dynamic solution and ensure it is an actual problem.
Let's say I have several functions defined like this:
template <typename T>
inline void read<bool>(T **data) {
//some code
}
template <typename T>
inline void read<double>(T **data) {
//some other code
}
template <typename T>
inline void read<int>(T **data) {
//also different code
}
Now, I create another function defined like this:
template<typename T>
inline void readMultiple(T **data, int counter) {
for (int i = 0; i < counter, ++i) {
read<T>(data);
}
}
(1)That would call the appropriate read<T>(T **data) implementation based on the type T, right?
(2)If I were to specify a type that is not one of the three above, I'd get a compilation error, since that function is not defined, right?
(3)Also, can I make this call:
double **d;
read<double>(d);
to ensure that I called the implementation for double?
I know I'd get the same result without the <double> part, but this way I'm ensuring that double is passed to the function, where as doing it without <double> would allow for d to be a int or a bool and the code would still compile, silently introducing an error.
(1)That would call the appropriate read<T>(T **data) implementation based on the type T, right?
Yes, assuming the specializations are visible at the point where read<T>(data) is encountered.
(2)If I were to specify a type that is not one of the three above, I'd get a compilation error, since that function is not defined, right?
You haven't provided your declaration of the template read() function, so this can't be answered. Assuming that you have declared it like template <typename T> void read(T**); and have not defined it anywhere then yes, you would get a link-time error when the linker is unable to find an implementation of the requested specialization.
(3)Also, can I make this call:
double **d;
read<double>(d);
to ensure that I called the implementation for double?
You can, though <double> is superfluous and will be inferred.
... silently introducing an error.
If the thing you're passing is a bool** then it would not be an error to use the bool specialization. I don't really see any benefit from explicitly providing the template arguments. If bool** is the wrong type then presumably you would be getting errors somewhere else, anyway.
I guess it depends on what you mean by "silently introducing an error." It's not clear what kind of error you're trying to prevent. I can come up with a contrived example, but contrived examples rarely represent real-world dangers.
Two side notes:
The syntax for your specializations is incorrect. It should be template <> inline void read<bool>(bool **data) { /* ... */ } for example.
There's no need for templates here at all, you can just have three function overloads. Having an undefined template function with explicit specializations is an anti-pattern; overloads are the recommended way to implement the same thing.
As you can see in the code below method get is templated.
struct A
{
int i;
char c;
};
class SL
{
static void* m_a;
public:
template <class T>
static T* get()
{
return static_cast<T*>(m_a);
}
};
void* SL::m_a = new A{12, 'C'};
int main()
{
std::cout << SL::get<A>()->i;
return 0;
}
What I do not understand is when I write SL::get<B>() how a compiler creates two methods with the same name, in the same namespace, with two different return types that both does not have parameters, i.e. does not have different argument list? How they overload each-other? Or it is wrong to understand temple function generation to have the same names and interpret their call via overload resolution?
Template instantions are really different functions which are not overloaded.
You may think of the template parameters <B> as a part of the function name.
So SL::get<A> and SL::get<B> are really different functions (though stemming from the same template).
Quoting from cppreference:
Template argument deduction takes place after the function template name lookup (which may involve argument-dependent lookup) and before overload resolution.
As you see, overload resolution is a different process.
This is compiler specific and you shouldn't worry about it too much. A general idea of how it's done though:
Say you call the templated method with 2 different types
SL::get<A>();
SL::get<B>();
The compiler generates 2 new methods for these calls:
static A* get_a()
{
// etc..
}
and
static B* get_b()
{
// etc..
}
This may differ from compiler to compiler but it shows how a compiler avoids name clashes. To the programmer, it's the same method being called twice, to a compiler it's just 2 different methods called by different pieces code.
Templates are prone to name mangling as anything else. When the exact get is generated, it's not really called get anymore, it will be called something like get#YUQIE or similar. You can check this article for an example. This is implementation-defined though, so different compilers will do it in a different way. For example, in the following code
template <class T>
T get()
{
return T();
}
int main()
{
get<int>();
get<char>();
return 0;
}
get was mangled by gcc as _Z3getIiEPT_v for get<int> and _Z3getIcEPT_v for get<char>.
Whenever I create a template I know to pass it in as function arguments, but is there any particular reason why I cannot use templates inside of my main function?
template <class Tmp>
int main()
{
Tmp pizza;
}
But passing as parameter will always work
template <class Tmp>
Tmp add(Tmp x, Tmp y)
{
return x+y;
}
The above code will not run and next to my attempted variable declaration line it state "Unknown type 'Tmp' ", but I assumed that because I declared template outside of my main function it would take this into account. Is there any particular reason why this is so? It seems as if everyone just uses templates inside function parameters and nothing more.
You're nearly there. But C++ is a statically-typed language, so the compiler needs to know the type for pizza at compile-time. This
template <class Y> struct/*members are public by default*/ Tmp
{
typedef Y type;
};
int main()
{
Tmp<int>::type pizza; /*pizza will be an int*/
}
is legal.
is there any particular reason why I cannot use templates inside of my main function
There's no reason you can't, but your code does not use templates inside your main function. Rather, your code is trying to define main to be a function template. This is no good, because the signature of main is specified in the standard and it's not a function template. Granted, implementations are permitted to specify alternatives, but this doesn't help you because your implementation doesn't specify any template function alternatives. My compiler (gcc) gives a more forthright error message than yours, it says:
error: cannot declare ‘::main’ to be a template
You are writing as if you believe that Tmp is called a template. If so, then correct that by looking back at your textbook/tutorial/whatever. Tmp is not a template. It is a template parameter. In your second code snippet, add is a function template, and Tmp is still not a template, it's the template parameter of add.
You can use template parameters inside the template whose parameters they are. For example, the following is fine:
template <class Tmp>
Tmp add(Tmp x, Tmp y)
{
Tmp total = x + y;
return total;
}
Your problem is just that when you tried this you tried it in main, which cannot be a template.
Templates are not code. Templates are ... well they are templates. Before you can call a template function it has to be instantiated. E.g.
template <class T> T foo(T x) { return T;}
This is just a template, ie if you write this alone the compiler will not create a single line of code for this. Only when you instantiate and use it the compiler will do something:
int main() {
int x = 0;
int y = foo<int>(x); // compiler instantiates the template and calls the int instance
}
In your first snippet the compiler does not know what type it should use to instantiate the template. Moreover, you cannot make main a template, because the entry point of any program has to be int main().
PS:
It seems as if everyone just uses templates inside function parameters and nothing more.
There are more things that one can do with templates. I like to think about templates as the way to parametrize my code whenever the parameter can be choosen at compile time. Consider this (a bit contrived) example:
// template taking a functor as argument
// (more precisely: a default constructible callable type)
template <typename op,typename T> void plug(T x) {
std::cout << "op(" << x << ") = " << op()(x) << "\n";
}
// a simple functor
template <typename T>
struct identity { T operator()(T x){return x;} };
int main() {
plug<identity<double>,double>(2.0);
}
// prints:
// op(2) = 2
Once instantiated, the parameter does not appear as function parameter, but it rather controls what the (templated) function is actually doing with its parameter.