2
votes

I'm a bit confused about templated member functions, let's suppose that we have some weird struct with a templated member function, like this:

struct Foo
{
    template <typename T> void f(T t) {};
};

And then, we store that struct into some standard container:

std::vector<Foo> V;

V.push_back(Foo());
V.push_back(Foo());
V.push_back(Foo());
V.push_back(Foo());

Next; let's call different instances of the templated member function:

V.at(0).f<int>(1);
V.at(0).f<char>(2);
V.at(1).f<float>(3.4f);
V.at(2).f<double>(5.6);
V.at(3).f<long>(7);

And finally, the questions:

¿All the instances of Foo class are from the same class? it seems that the answer is yes but... the first Foo instance has at the end two overloads of the f member function:

[0] Foo::f(int t);
[0] Foo::f(char t);

And in the other hand, the other Foo instances seems to have only one version of the f function. So apparently the base type of each instance is different due the differences on member functions.

[1] Foo::f(float t);
[2] Foo::f(double t);
[3] Foo::f(long t);

¿Where the f functions are instanced? apparently we can get the address of the Foo::f(int t) function only from first Foo instance, because that function only belongs to that instance; same for the other functions.

Thanks in advance.

4

4 Answers

7
votes

All the overloads are generated by the compiler for the Foo::f member function, you can think of it as having written all of them out by hand.

The overload generation (template instantiation) is not instance based, but rather it is class based, the class itself gets all the template instantiations splatted (just like having written all the overloads of the different types in the body of the class, for the given type T)

So this in your case:

struct Foo 
{     
   template <typename T> void f(T t) {}; 
}; 

would become (conceptually)

struct Foo 
{     
   void f<int>(int t) {}; 
   void f<char>(char t) {}; 
   void f<float>(float t) {}; 
   ...
   /// all the other uses of f with different types, anywhere in your code.
}; 

This is one of the reasons people argue against templates, it's called "code bloat".

1
votes

¿All the instances of Foo class are from the same class? it seems that the answer is yes

Yes, all of the instances are of the same type.

but... the first Foo instance has at the end two overloads of the f member function

Overloads are per-type, not per instance. The type will contain all of the overloads, regardless of what the object on which the template function was instantiated.

¿Where the f functions are instanced? apparently we can get the address of the Foo::f(int t) function only from first Foo instance, because that function only belongs to that instance; same for the other functions.

They are instantiated (compiled into binary code) by the compiler, where is not a proper question (other than in the binary). The address of the member function can only be obtained from the class, and not from any of the instances, as I already mentioned, the member functions are per-type, not per-instance of the type.

0
votes

All the Foo instances have all the overloads, and they are all of the same type since Foo itself is not a template class.

Functions are instantiated at compile time, in the object code.

0
votes

Let's look at a different example:

struct Foo
{
    void f(int);
    void f(double);
};

// ...
Foo foo1, foo2;
foo1.f(3);
foo2.f(3.0);

This is completely analogous to your own version, except that the compiler does not create new instantiations of the method f(). We only call method f(int) on foo1, and we only call method f(double) on foo2. Do you think they have different types now, just because we don't call all of the methods on every instance?

Methods are associated with classes, not with instances. All method overloads your code generates are methods of the class Foo, and all your instances have the same type.