I'm having troubles linking together different classes that uses the same templated class.

I found 2 workarounds, that will make it compile, but
it's not really a solution.
1. don't do a staged compiling with linking object code
2. inlining the spezialized member functions.

I'm looking for a solution that will make my templated class work just as nicely as the official stl's.


TemplatedFoo.h is an include guarded class definition that includes the implemention directly from TemplatedFoo.impl.

class1.cpp includes TemplatedFoo.h, and i can compile object code with 'g++ -c class1.cpp',
But when i try to link it with other stuff I get these kind of errors.

g++ ultra.cpp class1.o
class1.o: In function `Foo<float>::Foo(float)':
class1.cpp:(.text+0x128): multiple definition of `Foo<float>::Foo(float)'
/tmp/ccE4UJX8.o:ultra.cpp:(.text+0x6c): first defined here
class1.o: In function `Foo<float>::Foo(float)':
class1.cpp:(.text+0x17e): multiple definition of `Foo<float>::Foo(float)'
/tmp/ccE4UJX8.o:ultra.cpp:(.text+0x98): first defined here
class1.o: In function `Foo<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Foo(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
class1.cpp:(.text+0x1aa): multiple definition of `Foo<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Foo(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
/tmp/ccE4UJX8.o:ultra.cpp:(.text+0x1ae): first defined here
class1.o: In function `Foo<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Foo(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
class1.cpp:(.text+0x1fa): multiple definition of `Foo<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Foo(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
/tmp/ccE4UJX8.o:ultra.cpp:(.text+0x1fe): first defined here
collect2: ld returned 1 exit status

This is the code.

//TemplatedFoo.h
#ifndef TEMPLATED_FOO_H
#define TEMPLATED_FOO_H

template <typename T>
class Foo
{
public:
  Foo(const T value);
  T getValue() const;
    
private:
  T m_value;
};
#include "TemplatedFoo.impl"
//TemplatedFoo.impl
template <>
Foo<float>::Foo(const float value ) {
std::cout << "I do floats:\n";
  m_value = (value);
}

template <>
Foo<std::string>::Foo(const std::string val){
        std::cout << "I don't do strings:\n";
}

template <typename T>
T Foo<T>::getValue() const
{
          return m_value;
}
//class1.h
#include "TemplatedFoo.h"

class class1{
 public:
  class1(void);
  ~class1(void);
  int dummy_method(void);
  Foo<float> dummy_method2(void);
};
//class1.cpp
#include <iostream>

#include "TemplatedFoo.h"
#include "class1.h"


class1::class1(void){std::cout << "object constructed" << std::endl;}
class1::~class1(void){std::cout <<"object destructed" << std::endl;}
int class1::dummy_method(void){
  int ret = 2;
  return ret;
}
Foo<float> class1::dummy_method2(void){
  Foo<float> ret(4.0);
  return ret;
}
#include <iostream>
#include "class1.h"

int main(){
  std::cout<<"start of main\n";
  class1 cls1;
  std::cout <<"calling dummy method: "<< cls1.dummy_method()<<std::endl;
  Foo<float> var = cls1.dummy_method2();
  std::cout <<"calling dummy method2: " <<var.getValue()<<std::endl;
  std::cout<<"end of main\n";
}
//ultramain.cpp
#include <iostream>

#include "TemplatedFoo.h"
#include "class1.h"

int main(){
  std::cout<<"start of main\n";
  class1 cls1;
  std::cout <<"calling dummy method: "<< cls1.dummy_method()<<std::endl;
  Foo<float> var = cls1.dummy_method2();
  std::cout <<"calling dummy method2: " <<var.getValue()<<std::endl;
  std::cout<<"end of main\n";
}

This is just a simplified class of my larger program

thanks in advance

Recommended Answers

All 14 Replies

If "inlining the spezialized member functions" works, what's wrong with that solution? The only other thing I can think of (if I understand the problem) would be to put those functions in an object file of their own.

are you sure you have placed a #endif after the end of TemplatedFoo.h? if not, definately your code can provide you with trouble

Ok you have made several little errors/annoyances and one misunderstanding as I see it.

(a) First you #ifndef TEMPLATED_FOO_H does not finish

(b) You use a chained #include system. Please don't, it can be done but write .h file for the classes adn use #include's in the cxx. That will make g++ templates pleasing to read and readable in 6months time.

The major error: g++ has three ways of doing templates and you have not decided on any one of them.

Your can
(a) use -frepo : I don't because the compile time is horrific.
(b) You can include the whole class in the .h file and include it everywhere it is needed.
(c) use template instansiation.

I use (b) for container type classes e.g. Triple<A,B,C> which have lots of strange instances like Triple<int,double,std::string>. I use (c) for everything else.

You need a template class Foo<float>; at the base of your implementation of Foo. I am reposting a CUT version of your file that compiles.

#ifndef Foo_h
#define Foo_h

template <typename T>
class Foo
{
public:
  Foo(const T value);
  T getValue() const;    
private:
  T m_value;
};
#endif

and

#include <iostream>
#include <string>

#include "testAll.h"

template <>
Foo<float>::Foo(const float value ) 
{
  std::cout << "I do floats:\n";
  m_value = (value);
}

template <typename T>
T Foo<T>::getValue() const
{
  return m_value;
}

template class Foo<float>;

Note that if you want to use Foo<std::string> then you must add a template class Foo<std::string> in you implementation on class Foo.

NOTE: As you can see the problem with this is that you MUST have the full class header for each class you need in Foo. Thus you have a dependency problem. The advantage is that you gain compile speed and I am prepared to pay that (most of the time).

Thanks for you replies.

sorry there is indeed a #endif in file,
sorry for not copying the file correctly.

The problem arises when I compile a seperat object.
and try to link it with another object file that includes the same (but include guarded header file).

Does your problem persist with a instance in you Foo.cpp file??
e.g template class Foo<float>;

Hi stuxyz,
I just saw you had replied to my original post,
while I was replying,
So I didn't see it till know.

It's seems very informative and promising you post,
and i will for sure let you know how it goes.

thanks for you reply :)

Hi thanks for your replies, you have been very helpfull and informative.

But I'm afraid the problem persists.

I've simplefied my files even futher such that it should be simpler to check. ( only1 templated header with implementation in samefile)
Attached in the bottom of this post


@stuxyz
I've tried doing the instantiation of type
template class Foo<float>, in all files throughout the program, and none solves the problem.
That would be TemplatedFoo.h class1.h class1.cpp and ultra.cpp.
And your cutdown example doesn't really cover mine. Mine can compile as far as yours can, but I'm generating object code with another class using my templated class, and then try to link this with a main().
It's the last step that is causing the problem.

@siddhant3s
The problem to which you a refering is not really the same is mine. The poster has the problem of undefined refs, mine is multiple definitions.

I don't think the parashift example covers my problem,
since the returntype of one of the methods of class1 is a Foo<float>,
so that should be instantiated.

As I wrote in my original post the problem disappears magicly with inlining the function specializations. But this seems like a rude hack, with to much object code being compiled.

If I try to do the same with a stl type, there are no problems, does anyone know how they avoid this problem?

thanks again

//TemplatedFoo.h
#ifndef TEMPLATED_FOO_H
#define TEMPLATED_FOO_H

template <typename T>
class Foo
{
public:
  Foo(const T value);
  T getValue() const;

private:
  T m_value;
};

template <typename T>
//inline  <- works if uncommented
T Foo<T>::getValue() const{
  return m_value;
}

template <>
//inline  <- works if uncommented
Foo<float>::Foo(const float value ) {
  std::cout << "I do floats:\n";
  m_value = (value);
}

template <>
Foo<std::string>::Foo(const std::string val){
  std::cout << "I don't do strings:\n";
}
#endif
//class.h
class class1{
 public:
  class1(void);
  ~class1(void);
  int dummy_method(void);
  Foo<float> dummy_method2(void);
};
//class1.cpp
#include <iostream>

#include "TemplatedFoo.h"
#include "class1.h"

class1::class1(void){std::cout << "object constructed" << std::endl;}
class1::~class1(void){std::cout <<"object destructed" << std::endl;}

int class1::dummy_method(void){
  int ret = 2;
  return ret;
}
Foo<float> class1::dummy_method2(void){
  Foo<float> ret(4.0);
  return ret;
}
//ultra.cpp
#include <iostream>

#include "TemplatedFoo.h"
#include "class1.h"

int main(){
  std::cout<<"start of main\n";
  class1 cls1;
  std::cout <<"calling dummy method: "<< cls1.dummy_method()<<std::endl;
  Foo<float> var = cls1.dummy_method2();
  std::cout <<"calling dummy method2: " <<var.getValue()<<std::endl;
  std::cout<<"end of main\n";
}

Lets see what was the problem with the earlier approach. You were having one instance of TemplatedFoo.impl in your ultra.cpp and you were having another instance of TemplatedFoo.impl in the class1.cpp right? So, here is what the compiler did when you issued g++ ultra.cpp class1.o . He first already had compiled the the class1.cpp to make class1.o and as the TempletedFoo.impl was included in class1.cpp, all the definitions of

Foo<float>::Foo(const float value )  
Foo<std::string>::Foo(const std::string val)

got compiled within the class1.o. So now, all the definations are already in the class.o
Next what happened was, that the compiler now tried to compile ultra.cpp. Note that you indirectly had included the TemplatedFoo.impl also, right? But the compiler will compile this also, without consedering that you already have a compiled code for this. But now look what problem does the linker makes. Linker, while linking the two obj files class.o and ultra.o will find multiple definitions of all those function you defined in TemplatedFoo.impl

The later approach works because because you have not included the TemplatedFoo.h in your class.h hence the TemplatedFoo.impl does'nt get included in the ultra.cpp. Its not the "stl" aproach but it is something called, using-common-sense-while-including-files approach.
And don't worry, no one hits the jackpot at the first place.

Now, please summarize what all problem is left with your code.

Below I am going to post a working set of code.

The requirements are simple. You write an implimentation of foo and you put template class Foo<float> in that implimentation.
This is 99% portable and 100% within the standard. It works on portland, IBM, and g++. I don't have VC++ to test it against but I guess it will work there if you have it.

Next: The compile sequence is something like this:

g++ -c class1.cpp
g++ -c ultra.cpp
g++ -c foo.cpp

g++ -o ultra ultra.o class1.o foo.o

You compile one and only one instance of foo.cpp, which builds one and only one version of Foo<float>.

This route completely avoids the problem of hundreds of implimentations on each instances. Speeds compile time up hugely.
This is the normal route for any LARGE class which is only likely to have a few template instances. Sure with something like std::vector, you need to include it in a .h file since it (a) is a small class (b) has many different template instances in a code base.

// foo.cpp
#include <iostream>
#include "TemplatedFoo.h"

template <typename T>
//inline  <- works if uncommented
T Foo<T>::getValue() const{
  return m_value;
}

template <>
//inline  <- works if uncommented
Foo<float>::Foo(const float value ) {
  std::cout << "I do floats:\n";
  m_value = (value);
}

template <>
Foo<std::string>::Foo(const std::string val)
{
  std::cout << "I don't do strings:\n";
}

//THE BIT YOU KEEP MISSING: GOES HERE
template class Foo<float>;
// Templatedfoo.h
#ifndef TEMPLATED_FOO_H
#define TEMPLATED_FOO_H

template <typename T>
class Foo
{
public:
  Foo(const T value);
  T getValue() const;

private:
  T m_value;
};
#endif
//class1.h
class class1{
 public:
  class1(void);
  ~class1(void);
  int dummy_method(void);
  Foo<float> dummy_method2(void);
};
//class1.cpp
#include <iostream>

#include "TemplatedFoo.h"
#include "class1.h"

class1::class1(){std::cout << "object constructed" << std::endl;}
class1::~class1(){std::cout <<"object destructed" << std::endl;}

int class1::dummy_method(){
  int ret = 2;
  return ret;
}

Foo<float> class1::dummy_method2(){
  Foo<float> ret(4.0);
  return ret;
}

#include <iostream>

// ultra.cpp
#include "Templatedfoo.h"
#include "class1.h"
int main(){
  
  std::cout<<"start of main\n";
  class1 cls1;
  std::cout <<"calling dummy method: "<< cls1.dummy_method()<<std::endl;
  Foo<float> var = cls1.dummy_method2();
  std::cout <<"calling dummy method2: " <<var.getValue()<<std::endl;
  std::cout<<"end of main\n";
}
commented: very helpfull and throughly +1

thanks styxyz!
I haden't grasped, that I needed to
move implemention of my templatede class to a cpp file and add a
'templete class NAME<type>'
and compile object code and link with this file.

this is for sure the compile link model I will be using,
since I understand what's happening!

still
1)
I don't really understand why the inlining these specialized inlined member functions of templetes removes the multi def error.
2)
How the officiel stl libs does this.

But thanks for your very helpfull comments, codeexamples and commandline arguments.

Summary to the last two points:

1) Inlined IF THE COMPILER inlines it. Does exactly what it says on the tin. It takes the code for the function and writes in the code as if the function does not exist. Effectively you compile that bit many time but it is ok since it is as if you did this

// withouth func inlined:
int func(const int I)
{
   return I+18;
}

int sum(0);
if (x==5)
   sum+=func(j);
else
   sum+=func(j);
// Same code but func is inlined
int sum(0);
if (x==5)
   sum+=j+18
else
   sum+=j+18;

As you see the func has gone, hence it works. with multiple repeats.

2) The official stl: Note you will learn a lot by having a look at the code. Try the simple stuff first e.g. vector, pair.
But they include everything in the class definition and the standard says that is ok as long as the definitions are all the same. In practice the compiler can't check that except and link time BUT normally it doesn't. [Exception is Portland, sometime!]

ok thanks again for the clarification.
So just inling the stuff wont make the program safe,
since it's up to the compiler to decide if it wants to inline it.


about stl,
So they just have a huge class{} with the implemention directly inputtet.

If I do this, should my program the conform with old style
staged compiling.
that is compile everything to object code,
and then link?

Let me see what I think you question is, then answer that....
Not idea I know!

If you have a templated class and you put 100% of the implementation in the definition, shoudl you compile it in stages?

The answer to that question is that it doesn't matter. In a perfect world, with infinitely fast computers it doesn't matter since compiling takes zero time. In a real world, it takes a lot longer to compile so we split programs into parts, to get it to go faster.

If you put 100% of the implementation ino a definition AND
the class is large, then at each point that you include the definition you are going to have to pay a compilation large price. It still works BUT the c++ standard was written a long time ago when compilation too a LONG time and thus it allows the template instantiation.

If you compile all your code in one go, that is fine BUT you will take a lot longer each time that you make a change, than if you split it into parts and use a make file.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.