Jump to content

  • Log In with Google      Sign In   
  • Create Account


Not sure what it is that I'm doing wrong with templates in this case


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
18 replies to this topic

#1 ysg   Members   -  Reputation: 192

Like
0Likes
Like

Posted 07 April 2013 - 07:53 PM

Hi, I'm having a weird problem with templates. Here is the linker error that I'm getting (in bold):
% make clean && time make
rm -rf *o main
g++ -c -g generic-stack.cpp
g++ -c -g main.cpp
g++ -c -g stack.cpp
g++ -c -g enhanced-stack.cpp
g++ -c -g base-stack.cpp
g++ -c -g array-stack.cpp
g++ -c -g list-stack.cpp
g++ main.o generic-stack.o stack.o enhanced-stack.o base-stack.o array-stack.o list-stack.o -o main
[b]Undefined symbols for architecture x86_64[/b]:
  "GENERIC_STACK<int>::GENERIC_STACK()", referenced from:
      _main in main.o
  "GENERIC_STACK<int>::~GENERIC_STACK()", referenced from:
      _main in main.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [main] Error 1
Here is the header file:
#ifndef GENERIC_STACK_HPP
#define GENERIC_STACK_HPP

#include "global-includes.hpp"

template <typename T>
class GENERIC_STACK
{
  public:
    GENERIC_STACK();
    ~GENERIC_STACK();
    void Push(T value);
    T Pop();
    bool Is_Empty();

  private:
  protected:
    struct NODE
    {
      T value;
      NODE * link;
    };

    NODE * Head;
};

#endif
Here is a source file:
#include "generic-stack.hpp"

template <typename T>
GENERIC_STACK<T>::GENERIC_STACK()
{
  Head = NULL;
}

template <typename T>
GENERIC_STACK<T>::~GENERIC_STACK()
{
  T value;

  while(!Is_Empty())
  {
    Pop(value);
  }
}

template <typename T>
void GENERIC_STACK<T>::Push(T value)
{
  NODE * temp = new NODE;
  temp->value = value;
  temp->link = Head;
  Head = temp;
}

template <typename T>
T GENERIC_STACK<T>::Pop()
{
  T value;
  NODE * temp = Head;
  value = Head->value;
  Head = Head->link;
  delete temp;
}

template <typename T>
bool GENERIC_STACK<T>::Is_Empty()
{
  return Head == NULL;
}
This is the main method:
#include "new-stack.hpp"
#include "list-stack.hpp"
#include "array-stack.hpp"
#include "generic-stack.hpp"

int main(int argc, char * argv[])
{
  ...


  GENERIC_STACK<int> int_stack;

  return 0;
}
Two things I'd like to add:
1 - I know that standards-wise, this code is ugly. This is just my temporary thing that I'm using to remember about C++.
2 - "global-includes.hpp" includes stuff like #include <iostream>, etc.

Now, my question, why am I getting this ugly error? I've checked my Makefile and that looks good (below) and I don't understand why this is happening.

Makefile
all: main

main: generic-stack.o main.o stack.o enhanced-stack.o base-stack.o array-stack.o list-stack.o
	g++ main.o generic-stack.o stack.o enhanced-stack.o base-stack.o array-stack.o list-stack.o -o main

generic-stack.o: generic-stack.cpp
	g++ -c -g generic-stack.cpp

base-stack.o: base-stack.cpp
	g++ -c -g base-stack.cpp

array-stack.o: array-stack.cpp
	g++ -c -g array-stack.cpp

list-stack.o: list-stack.cpp
	g++ -c -g list-stack.cpp

stack.o: stack.cpp
	g++ -c -g stack.cpp

enhanced-stack.o: enhanced-stack.cpp
	g++ -c -g enhanced-stack.cpp

new-stack.o: new-stack.cpp
	g++ -c -g new-stack.cpp

main.o: main.cpp
	g++ -c -g main.cpp

clean:
	rm -rf *o main
Thoughts?

[edit]

Yes, I googled, no I could not find an answer that helped me.

Edited by ysg, 07 April 2013 - 07:55 PM.


Sponsor:

#2 SiCrane   Moderators   -  Reputation: 9388

Like
0Likes
Like

Posted 07 April 2013 - 08:10 PM

Long story short, you can't separate template definitions into their own source file (without special compiler support that almost no compiler has, or unless you what to manually instantiate the templates for each type you want to use). Put the template functions into the header file.

#3 ysg   Members   -  Reputation: 192

Like
0Likes
Like

Posted 07 April 2013 - 08:12 PM

So put the source code in the header file?

#4 AllEightUp   Moderators   -  Reputation: 4118

Like
0Likes
Like

Posted 07 April 2013 - 08:49 PM

So put the source code in the header file?

 

That is the common solution.  The other solution as mentioned is to do something like:

 

 

template GENERIC_STACK< int >;

 

in the source to force implementation of a specific version of the template.  (I believe I have that correct, rarely implement a full class that way, just members.)

 

PS. this is not a good idea in general, putting the code in the header to be generated at compile time is better than forcing a compile time generation of the entire class.


Edited by AllEightUp, 07 April 2013 - 08:50 PM.


#5 ysg   Members   -  Reputation: 192

Like
0Likes
Like

Posted 07 April 2013 - 09:07 PM


So put the source code in the header file?

 
That is the common solution.  The other solution as mentioned is to do something like:
 
 
template GENERIC_STACK< int >;
 
in the source to force implementation of a specific version of the template.  (I believe I have that correct, rarely implement a full class that way, just members.)
 
PS. this is not a good idea in general, putting the code in the header to be generated at compile time is better than forcing a compile time generation of the entire class.


Yeah, I'd like to avoid that if I can smile.png .

#6 AllEightUp   Moderators   -  Reputation: 4118

Like
0Likes
Like

Posted 07 April 2013 - 09:23 PM


PS. this is not a good idea in general, putting the code in the header to be generated at compile time is better than forcing a compile time generation of the entire class.

 

Yeah, I'd like to avoid that if I can smile.png .

 

You get a gold star for that.  I used to use ".inl" files to separate the class definition in the standard 'header' file from the 'inline' file, but Xcode ignores the '.inl' files and you can't debug through them or set breakpoints, so you have to use 'h' or 'hpp' on that platform.  (I'm sure you can customize it, I refuse to do so though, might make things nice for me but others working with the codebase may not have all the customizations)  Of course, it is non-standard and as such probably not a great thing to do, but it was nice.  I could put the declaration of the interface in an hpp, the inline function definitions in a inl and any non-template parameter specific stuff in a cpp where I used the explicit definition as posted above to make the compiler generate the code.



#7 Josh Vega   Crossbones+   -  Reputation: 1147

Like
1Likes
Like

Posted 07 April 2013 - 10:07 PM

Not to try and prove you all wrong or anything, but I found this article a while ago which says that it is possible to separate the declarations and definitions for template functions into .h and .cpp files. It does seem though (from the sample compiler/linker messages he provides) that he's using MSVC rather than GCC.

 

I use templates in some of my projects and have been using "Method 1" (or as he writes, "Mehtod 1") to get around linking errors. Although, I too use only MSVC (haven't gotten a chance to learn how to use GNU tools yet).

 

EDIT: Fixed typo.


Edited by Josh Vega, 07 April 2013 - 10:08 PM.

Some favourite quotes:
Spoiler

#8 kloffy   Members   -  Reputation: 865

Like
0Likes
Like

Posted 07 April 2013 - 11:45 PM

I use templates in some of my projects and have been using "Method 1" (or as he writes, "Mehtod 1") to get around linking errors. Although, I too use only MSVC (haven't gotten a chance to learn how to use GNU tools yet).

It looks like "Method 1" is just a backward way to get explicit template instantiation (as mentioned by SiCrane). I think the usual syntax would be something like:

template class GENERIC_STACK<int>;

 

Edit: And "Method 3" is generally done like AllEightUp described (all code ends up in the header)...


Edited by kloffy, 07 April 2013 - 11:52 PM.


#9 ysg   Members   -  Reputation: 192

Like
0Likes
Like

Posted 08 April 2013 - 05:17 AM

Oh, any real difference between say template <typename T> and template <class T>? I tend to use the former by habit.

#10 ysg   Members   -  Reputation: 192

Like
0Likes
Like

Posted 08 April 2013 - 05:20 AM

Not to try and prove you all wrong or anything, but I found this article a while ago which says that it is possible to separate the declarations and definitions for template functions into .h and .cpp files. It does seem though (from the sample compiler/linker messages he provides) that he's using MSVC rather than GCC.
 
I use templates in some of my projects and have been using "Method 1" (or as he writes, "Mehtod 1") to get around linking errors. Although, I too use only MSVC (haven't gotten a chance to learn how to use GNU tools yet).
 
EDIT: Fixed typo.

As ugly as it is, Method #3 is probably the best possible solution.

#11 ysg   Members   -  Reputation: 192

Like
0Likes
Like

Posted 08 April 2013 - 05:21 AM



PS. this is not a good idea in general, putting the code in the header to be generated at compile time is better than forcing a compile time generation of the entire class.

Yeah, I'd like to avoid that if I can smile.png .


 
You get a gold star for that.  I used to use ".inl" files to separate the class definition in the standard 'header' file from the 'inline' file, but Xcode ignores the '.inl' files and you can't debug through them or set breakpoints, so you have to use 'h' or 'hpp' on that platform.  (I'm sure you can customize it, I refuse to do so though, might make things nice for me but others working with the codebase may not have all the customizations)  Of course, it is non-standard and as such probably not a great thing to do, but it was nice.  I could put the declaration of the interface in an hpp, the inline function definitions in a inl and any non-template parameter specific stuff in a cpp where I used the explicit definition as posted above to make the compiler generate the code.


On a side-note, why do you have "Crossbones+" next to your username?

#12 Nercury   Crossbones+   -  Reputation: 766

Like
0Likes
Like

Posted 08 April 2013 - 07:31 AM

The approach I use is this (seems like "Method 3"):

 

// template_file.h

#pragma once

/* YOUR TEMPLATE DECLARATION HERE */

#include <template_file.inline.h>

 

And definitions:

 

// template_file.inline.h

#pragma once
#include <template_file.h>

/* DEFINITIONS HERE */

 

 

"inline" file is used like a usual .cpp file. This speeds up compilation a lot.

Sadly, I don't remember where I first found this approach.

 

Edit: you can replace "pragma once" with "#ifndef .., #define ..". Same thing.


Edited by Nercury, 08 April 2013 - 07:34 AM.


#13 Cornstalks   Crossbones+   -  Reputation: 6966

Like
1Likes
Like

Posted 08 April 2013 - 07:43 AM

On a side-note, why do you have "Crossbones+" next to your username?

It's for people who are contributing to the site (through articles):

Screen Shot 2013-04-08 at 7.40.43 AM.png

 

I was going to add more to this thread but most of what I would've said has already been said.


[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#14 Josh Vega   Crossbones+   -  Reputation: 1147

Like
0Likes
Like

Posted 08 April 2013 - 08:06 AM

On a side-note, why do you have "Crossbones+" next to your username?

It's for people who are contributing to the site (through articles):

attachicon.gifScreen Shot 2013-04-08 at 7.40.43 AM.png

 

I was going to add more to this thread but most of what I would've said has already been said.

 

Sadly though, I have yet to find the time to write my first article... sad.png


Some favourite quotes:
Spoiler

#15 ysg   Members   -  Reputation: 192

Like
0Likes
Like

Posted 08 April 2013 - 08:22 AM

The approach I use is this (seems like "Method 3"):

// template_file.h

#pragma once

/* YOUR TEMPLATE DECLARATION HERE */

#include <template_file.inline.h>
 
And definitions:
 
// template_file.inline.h

#pragma once
#include <template_file.h>

/* DEFINITIONS HERE */
 
 
"inline" file is used like a usual .cpp file. This speeds up compilation a lot.
Sadly, I don't remember where I first found this approach.
 
Edit: you can replace "pragma once" with "#ifndef .., #define ..". Same thing.


Ok, so you have two header files?

Having a hard time visualizing your approach. The way I understand it is this:
- template-file.hpp: this is where you have the class declaration (and the sub-methods)
- template-file.inline.hpp: this is a just a place-holder file to make it easier for the compiler to swallow
- template-file.cpp: this is where the implementation of the template class is located

Am I right or am I way off?

#16 kloffy   Members   -  Reputation: 865

Like
0Likes
Like

Posted 08 April 2013 - 09:09 AM

The approach I use is this (seems like "Method 3"):
 

// template_file.h

#pragma once

/* YOUR TEMPLATE DECLARATION HERE */

#include <template_file.inline.h>
 
And definitions:
 
// template_file.inline.h

#pragma once
#include <template_file.h>

/* DEFINITIONS HERE */
 
 
"inline" file is used like a usual .cpp file. This speeds up compilation a lot.
Sadly, I don't remember where I first found this approach.
 
Edit: you can replace "pragma once" with "#ifndef .., #define ..". Same thing.

For most purposes, this is probably the best way to go. Only one thing:

 

#include <template_file.h>

 

This line in "template_file.inline.h" is redundant, unless you include "template_file.inline.h" from somewhere else and are not sure if "template_file.h" will be included beforehand. Otherwise the include guards just do their job. In my opinion, it is cleaner to just say that the "*.inline.h" files are not for use outside of "*.h".

@ysg: There is no "*.cpp". The "#include" directive basically inserts the plain text from the included file verbatim. From the compilers view, everything ends up inside the header. The inline files containing the implementation are just for organization.


Edited by kloffy, 08 April 2013 - 09:12 AM.


#17 Nercury   Crossbones+   -  Reputation: 766

Like
1Likes
Like

Posted 08 April 2013 - 09:15 AM

The approach I use is this (seems like "Method 3"):
 

// template_file.h

#pragma once

/* YOUR TEMPLATE DECLARATION HERE */

#include <template_file.inline.h>
 
And definitions:
 
// template_file.inline.h

#pragma once
#include <template_file.h>

/* DEFINITIONS HERE */
 
 
"inline" file is used like a usual .cpp file. This speeds up compilation a lot.
Sadly, I don't remember where I first found this approach.
 
Edit: you can replace "pragma once" with "#ifndef .., #define ..". Same thing.

 

Ok, so you have two header files?

Having a hard time visualizing your approach. The way I understand it is this:
- template-file.hpp: this is where you have the class declaration (and the sub-methods)
- template-file.inline.hpp: this is a just a place-holder file to make it easier for the compiler to swallow
- template-file.cpp: this is where the implementation of the template class is located

Am I right or am I way off?

 

No, implementation is in template-file.inline.hpp, because there is no .cpp file. Template files are inlined anyways per-use. Or, should I say, compiler chooses how and where to compile multiple binaries resulting from used variations of the template parameters.

 

You would include template-file.hpp in other files to use template.


Edited by Nercury, 08 April 2013 - 09:16 AM.


#18 SiCrane   Moderators   -  Reputation: 9388

Like
0Likes
Like

Posted 08 April 2013 - 09:33 AM

For maximum fun, some people have three headers per template class: one containing the class definition without the member function definitions, one containing the member function definitions, and one containing a forward declaration for the template class and any common typedefs involving the template class. The last is useful since template classes can have non-trivial forward declarations.

#19 ysg   Members   -  Reputation: 192

Like
0Likes
Like

Posted 08 April 2013 - 09:35 AM

For maximum fun, some people have three headers per template class: one containing the class definition without the member function definitions, one containing the member function definitions, and one containing a forward declaration for the template class and any common typedefs involving the template class. The last is useful since template classes can have non-trivial forward declarations.

Nah, I'm good with the current level of "fun"/complexity/insanity smile.png .




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS