C/C++ How Can I Fix Template and Non-Member Function Issues in MS Visual Studio C++?

  • Thread starter Thread starter AlephZero
  • Start date Start date
  • Tags Tags
    C++ Visual
AI Thread Summary
The discussion revolves around issues encountered when trying to split a template function, `mytest`, into a separate .cpp file in a C++ project. The initial code compiles but leads to linker errors indicating unresolved external symbols for the template instantiations. Participants clarify that template functions must be defined in header files because their instantiation occurs only when used. A proposed solution involves explicitly instantiating the template for specific types in the .cpp file, which allows the function definitions to remain outside the header files. Despite concerns about code size and organization, it is emphasized that the standard practice is to include templates in headers, often marked as inline, to avoid complications. The conversation touches on the balance between optimization and practicality in coding practices, particularly in the context of a project involving code porting and language conversion.
AlephZero
Science Advisor
Homework Helper
Messages
6,983
Reaction score
299
This little test of templates and non-member functions works fine:

Code:
// test5.cpp : main project file.

#include "stdafx.h"

using namespace System;

	template <class T> void mytest(void);

	int main(array<System::String ^> ^args)
	{
		mytest<double>();
		mytest<int>();
		Console::ReadLine();
		return 0;
	}

	template <class T> void mytest (void)
	{
		T x = 1;
		T y = 2;
		Console::WriteLine("size of T = {0} x/y = {1}",sizeof(T),x/y);
	}

I want to split this up so function mytest is in its own .cpp file, but I can't get it to work.

It compiles OK but I get
Code:
test5.obj : error LNK2028: unresolved token (0A000006) "void __cdecl mytest<int>(void)" (??$mytest@H@@$$FYAXXZ) referenced in function "int __clrcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@System@@@Z)
test5.obj : error LNK2028: unresolved token (0A000007) "void __cdecl mytest<double>(void)" (??$mytest@N@@$$FYAXXZ) referenced in function "int __clrcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@System@@@Z)
test5.obj : error LNK2019: unresolved external symbol "void __cdecl mytest<int>(void)" (??$mytest@H@@$$FYAXXZ) referenced in function "int __clrcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@System@@@Z)
test5.obj : error LNK2019: unresolved external symbol "void __cdecl mytest<double>(void)" (??$mytest@N@@$$FYAXXZ) referenced in function "int __clrcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@System@@@Z)
which suggests it doesn't realize it has to instantiate the templates.

What am I doing wrong? FWIW changing "class T" to "typename T" makes no difference.
 
Technology news on Phys.org
You don't forward declare template functions. It doesn't make sense. Put the template definition above your main and all should be fine.
 
AlephZero said:
I want to split this up so function mytest is in its own .cpp file, but I can't get it to work.

I guess you have (two) different cpp files, each containing part of the code? Are both parts of the same project? Perhaps linker has no idea where to look for the compiled code.
 
Usually you are forced to put the entire template function (including body) in a header file.
This is necessary since the expansion into code only takes place when it's actually used.
Just like an old style C macro.
 
Borek said:
I guess you have (two) different cpp files, each containing part of the code? Are both parts of the same project? Perhaps linker has no idea where to look for the compiled code.

Yes the two files are part of the same project.

I like Serena said:
Usually you are forced to put the entire template function (including body) in a header file.
This is necessary since the expansion into code only takes place when it's actually used.
Just like an old style C macro.

Yes ... (as with DH's reply) ... except this will finish up as a big library of non-class functions, and the idea of including maybe 106 lines of code in header file(s) doesn't seem the right way to go, and neither does creating an intricate logical structure to dissect it into smaller pieces.

Actually, I've stumbled across a reasonably good solution in the MS documentation. You can explicitly instantiate a template function like this:

Code:
// file mytest.cpp

template <class T> void mytest (void);

template void mytest <int> (void);
template void mytest <double> (void);

template <class T> void mytest (void)
	{
		T x = 1;
		T y = 2;
		Console::WriteLine("size of T = {0} x/y = {1}",sizeof(T),x/y);
	}

And then call them in another file.

That will probably work OK for me, because most of the time I know in advance what classes I want to instantiate, and it will keep the function definitions out of the header files.

Thanks all.
 
Last edited:
AlephZero said:
Yes ... (as with DH's reply) ... except this will finish up as a big library of non-class functions, and the idea of including maybe 106 lines of code in header file(s) doesn't seem the right way to go, and neither does creating an intricate logical structure to dissect it into smaller pieces.
What makes you think you will get 106 lines of code in header files? I think this is a case of premature optimization. "Premature optimization is the root of all evil (or at least most of it) in programming." (Donald Knuth). Don't worry about problems that don't exist.

The standard approach with templates is to put them into headers. When you do that, you typically declare your free function templates as inline.
 
D H said:
What makes you think you will get 106 lines of code in header files?

It's a code porting (and language conversion) project, so I know where I'm starting from. And as with most "computer archeology" type projects, that isn't the place one would want to start from given a free choice...
 
Back
Top