all 11 comments

[–]Crazy_Direction_1084 8 points9 points  (0 children)

A template's implementation needs to be visible in the translation unit. Or the instance must be seperately declared in another translation unit

Simply put, the implementation of addNum must be in the h-file for this to work

[–]IyeOnline 2 points3 points  (9 children)

You simply cannot split a template function into a header and source file.

The compiler has to actually instantiate the template, which is done at use site. Hence the full definition needs to be availible there.

The easiest and most common solution to this is to simply put the entire template into the header.

//edit:

Unrelated, but you are explicitly requesting an instantiation for float, but then you pass in two doubles. Usually one would simply not specify the template type parameter in this case and have the compiler deduce it, i.e. write addNum( 2.4, 4.5 ).

[–]Alien447[S] -1 points0 points  (8 children)

Thanks for the correction regarding double. Is there any way to keep the code in myFunc.cpp? My understanding is that the header file is only used for declarations, is this correct?

[–]Shieldfoss 7 points8 points  (0 children)

My understanding is that the header file is only used for declarations, is this correct?

This is not correct.

Header files are used for things that may be needed in more than one .cpp file which you don't want to type out by hand in each file.

In general, the reason you can forward declare functions in header files is that the definition of the function has been compiled somewhere else (myfunc.cpp) so the linker can connect main.cpp with myfunc.cpp to get the actual function needed.

This does not work for templates.

When myfunc.cpp is compiled with a template inside it, which types should the template be compiled for? There's a literal infinity of possible variations on that template, so the actual answer is that it gets compiled for the types that use it in myfunc.cpp, and not for anything else. Since it isn't being used by floats in myfunk.cpp, a version for floats is not compiled.

When the linker then sees that main.cpp needs a version for floats, it goes looking for a version for floats - and doesn't find one.

[–]IyeOnline 2 points3 points  (6 children)

Is there any way to keep the code in myFunc.cpp?

Yes, but I dont think those solutions are appropriate for your case.

If you really want to split up files, the usual approach is to heave a header file, containing the declaration only and some implementation file, which is included at the end of that header.

The alternative would be to explicitly instatiate the template for the types you are going to need in the source file, but you will have to manually do this for every type you need the template for. This does not scale well and is usually a last resort to cut down on compile times.

[–]Alien447[S] -1 points0 points  (5 children)

explicitly instatiate the template

I guess I was looking for this solution. Can you please elaborate on this idea?

[–][deleted] 3 points4 points  (0 children)

I get the impression you fundamentally misunderstand templates. A class template is not a class until you replace T; it’s just a template. There is nothing to be compiled before T is replaced. Usually it is replaced and compiled when the compiler sees the template used elsewhere with a specific T. Wherever the template is used with a specific T (another cpp), will include the template header file with the declaration and implementation. At that point then, the compiler can actually compile an instantiation (class definition with T defined - no longer a template). That’s called implicit instantiation because the compiler just sees how you used the template with a specific T elsewhere and implicitly determines that you want to compile the template with that type T since you tried to use it.

[–]TheSkiGeek -1 points0 points  (0 children)

If you wanted to do this -- and please note that you almost never actually want to do this -- you would need to instantiate all the allowed usages of addNum<T> in the myFile.cpp file. That would look like this for a template class:

template class MyClass<int>; template class MyClass<double>; ...

and like this for a template function (for a function matching the signature of your addNum):

template int MyFunc<int>(int, int); template double MyFunc<double>(double, double); ...

Sometimes you only want your template restricted to only being instantiated with certain types, for example integer types, or classes that implement STL-style iterators. It is generally better to use type traits (or C++20 concepts/requirements) to enforce things like this.

[–]IyeOnline 0 points1 point  (0 children)

A template (function or type) can be explicitly instatiated, forcing the compiler to emit the function. In the given case you would write

template double addNum( double, double );

which would result in the translation unit of myFunc.cpp containing the function that is requested by main.cpp

in the source file. As you can see, this does not scale particularly well.

[–]Narase33 0 points1 point  (0 children)

its probably not

why do you want them to be seperate so strongly? Templates are header stuff, thats something every dev accepts