2

The compiler says it can't find the reference for the function when I do this:

// link.h
template <class T>
    T *Link(T *&, T *(*)())

// link.cpp
template <class T>
T c:Link(T *&ChildNodeReference, T *(*ObjectCreator)()){

}

If I implement inside the class on the header it goes smoothly.

Please, I will work on the header until someone enlightens me about this.

There are somethings in C++ that are weirdly annoying. I know, there is a reason for this and etc. Even so, can't the compilers help you out about it -_-"

Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
Jonathan
  • 4,724
  • 7
  • 45
  • 65

5 Answers5

6

Templates are essentially semi-type-safe macros, hence the limitation.

Normal (non-template) functions can be compiled to native code residing object/library files, and then referenced with only a prototype available in the header, solely because there's only a single version of such a function.

With templates, C++ compiler has to compile each instantiation of the function separately. Obviously, it cannot do it "in advance", because the set of types for which you can instantiate the function is effectively unbounded (you can always define a new type in your code before calling the function). In fact, two instantiations of the same function template can be completely different. Consider this extreme case:

struct t1 {
  template <int>
  struct a {};
};

struct t2 {
  enum { a = 123 }; 
};

enum { b = 456, c = 789 };

template <class T>
void foo() {
   T::a<b>c;
}

Now if we call foo<t1>(), the statement inside it is a local variable declaration, because t1::a is a class template:

T::a<b> c;

But if we call foo<t2>(), the statement inside is an expression, because t2::a is an integral constant:

(T::a < b) > c;

This is just to show that compiler cannot meaningfully "compile" a template; it really has to mostly preserve the tokens.

Now, all that said, ISO C++ does actually provide the ability to separate declaration and definition of templates, so that they can be treated as normal functions, with declarations in .h files, and definitions in .cpp files. This is called "export templates", because you have to precede both declaration and definiton with keyword export:

// link.h
export template <class T>
T *Link(T *&, T *(*)());

// link.cpp
export template <class T>
T *Link(T *&ChildNodeReference, T *(*ObjectCreator)()) {
}

This is, however, a controversial feature of the Standard because of very high burden on implementation, and most popular implementations refuse to implement it; notably, g++, MSVC, and C++Builder do not implement it. The only compiler I know of that supports it is Comeau C++.

Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
  • 1
    The problem is simplified if the types to be used in a template are known a priori. For example, if a function is a template for int, char and float numbers, one can declare the template function with these types in the header file and define the template in the cpp file. See http://www.parashift.com/c++-faq-lite/templates.html#faq-35.13 – user193272 Oct 23 '09 at 03:29
  • I believe `T::a` must be spelled `T::template a` in order to compile with a conforming compiler. That's because otherwise the compiler couldn't even do minimal plausibility checks for the code in the template for exactly the reason you're giving. – sbi Dec 09 '10 at 22:04
5

Programming non-template code or non-inlined functions in headers is a Bad Thing™. The reason you have cpp files is to prevent redefinition of the same function code more than once, amongst other things.

The difference with templates is that the compiler practically doesn't touch them until your code instantiates a specialisation of that template which is why they need to have their source inside the header.

When the compiler finds an instantiation of a template specialisation (say List<int>), it goes back to the included template code and compiles it with that specialisation, which is why you don't have issues with redefinition of function code.

What you don't seem to understand is that this doesn't apply to non-templated code. All non-template code is compiled as normal and thus CPP files are needed to only define the code once then link it all together.

If you define functions inside a header, your linker will not link the compiled translation units because they have defined the same function more than once.

Nick Bedford
  • 4,365
  • 30
  • 36
4

Templated implementations (not only definitions) have to be available at compile time.

So, the full template code is normally put in the header file.

gnud
  • 77,584
  • 5
  • 64
  • 78
  • aren't my .cpp units being compiled as well? why normal functions are ok and not the templated ones? is there anyway to not have to put my hard work obvious to others? – Jonathan Oct 06 '09 at 22:32
  • Template classes and functions are only compiled when they are used, so the code inside the functions must be present for the compiler to be able to instantiate specific types. – Nick Bedford Oct 06 '09 at 22:33
  • so why do we have the .cpp files? we should all programm at the header file, because we can't split the classes for better and organized public libraries and we can't code templated classes at the unit... this looks like c# more each time I try new stuff. – Jonathan Oct 06 '09 at 22:37
  • Templates are the exception, Jonathan. Templates in C++ work fundamentally different from C#/Java Generics. Have a look at http://blogs.msdn.com/csharpfaq/archive/2004/03/12/88913.aspx – gnud Oct 06 '09 at 22:59
0

Template code must be in the header. Sorry, I completely missed that! (and I thought I'd been coding C++ for years :P)

Nick Bedford
  • 4,365
  • 30
  • 36
  • there is no other way? seriously, why does someone bother to create .cpp units if you can't just use it seriously, I had so much expectations of freedom in coding and C++ is letting me down... – Jonathan Oct 06 '09 at 22:34
  • Templates are the only part of C++ which require this (other than inline functions). CPP units are heavily utilised everywhere else. A header is just code placed into source file which is then compiled. There's nothing special about cpp files. Templates must be provided with full source otherwise the compiler has no function code to compile. its just the way C++ works. – Nick Bedford Oct 06 '09 at 22:44
0

You forgot the * for the return type. So implementation is not matching definition. Add it and it should work:

T *c:Link(T *&ChildNodeReference, T *(*ObjectCreator)())
{
}

Implementation must be too in the header file under the class definition in order to be available at compile time.

Patrice Bernassola
  • 14,136
  • 6
  • 46
  • 59