template declaration

Hi

I would like to declare a template class object in my  .h header file and instantiate it in the .cpp file.

Is there a way to do this?

Eg;
A.h

ClassTemplate<int> myObj; //I do not want to call the default constructor here


A.cpp

myObj(3);  //I want to instantiate it here and use a non-default constructor, one that take an int as its parameter
LuckyLucksAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

evilrixSenior Software Engineer (Avast)Commented:
Okay, so first of all the following article I wrote about splitting declaration and definition of templates, which might be helpful.

http://www.experts-exchange.com/articles/1199/Separating-C-template-declaration-and-implementation.html

You can certainly declare a specialised object of a template but at the "point of instantiation" the full definition of the template MUST be visible to the compiler. You would need to extern declare the template class specialisation in the header and include the full definition of the template class you wish to use in the .cpp file.

This is the syntax you want:

///////////////////////////////////////////////////////////////////////////////
// ClassTemplate.hpp

#pragma once

#include <iostream>

template <typename T>
class ClassTemplate
{
public:
   ClassTemplate()
   {
      std::cout << "ClassTemplate constructor" << std::endl;
   }

   void Test()
   {
      std::cout << "ClassTemplate Test" << std::endl;
   }
};

///////////////////////////////////////////////////////////////////////////////
// a.hpp

#pragma once

// declare that somewhere this will be defined
extern ClassTemplate<int> obj; // NOT constructed here!

class A
{
   public:
      A()
      {
         // use it
         obj.Test();
      }
};

///////////////////////////////////////////////////////////////////////////////
// a.cpp

#include "ClassTemplate.hpp"
#include "a.hpp"

// create object (point of instantiation)
ClassTemplate<int> obj;

int main( int argc, char ** argv )
{
   A a; // construct A, which uses obj
}

///////////////////////////////////////////////////////////////////////////////

Open in new window


Not sure why you would want to do this, though so maybe I've misunderstood what you are asking for?
0
phoffricCommented:
>> Not sure why you would want to do this
One reason for separating the template body from the template class header is to avoid code bloat. Another possible reason is to hide the implementation of the body from the users so that they don't become overly connected to the mechanisms behind the methods, or if the users purchase your libraries and you don't want them to see your proprietary methods. (Ok, there's also pimpl.)

This link shows you how to separate the template class definition from its implementation:
https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl

In your case, your .cpp file should include
template class ClassTemplate<int>;

Open in new window


If later you need ClassTemplate to be defined for another type, say UDT, then you would have to have something like this:
#include "UDT.hpp"
template class ClassTemplate<UDT>;

Open in new window

0
phoffricCommented:
>> myObj(3);  //I want to instantiate it here and use a non-default constructor, one that take an int as its parameter

Forgetting about templates for a moment, if you have a class definition defined in Foo.hpp and its implementation defined in Foo.cpp, then normally, we do not instantiate the class Foo in these two files. Another .cpp file, for example, main(), will typically instantiate it.

This applies naturally to your template case as well.
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

evilrixSenior Software Engineer (Avast)Commented:
>> One reason for separating the template body from the template class header is to avoid code bloat.
This doesn't solve that. The compiler MUST have full visibility of ALL the template code before the POI.

C++ used to provide the "export" keyword to allow template implementation to be separate from the main class body, but this never worked as expected and was deprecated in C++11. The  proper way to implement templates, as from C++11, is in the header file. You can still separate the definition and implementation.

// All this is in a single header file

// class definition
template <typename T>
class foo
{
   void bar();
};

// class implementation
template <typename T>
void foo::bar()
{
}

Open in new window


Another way of doing this is using this idiom

// foo.ipp

// class implementation
template <typename T>
void foo::bar()
{
}


// foo.hpp

// class definition
template <typename T>
class foo
{
   void bar();
};

// include class implementation
#include "foo.ipp"

Open in new window


The idea of just declaring an instance of a specialisation doesn't really solve this. Or have I misunderstood what you meant?

>> Another possible reason is to hide the implementation of the body from the users
This would give you the ability to use "myObj" without exposing the implementation but it would NOT allow you to re-use the ClassTemplate<T> definition anywhere else. Unlike normal classes where you can have the implementation in a library, a template class MUST be visible at the POI. Putting implementation in a translation unit will result in linking errors if you try to use create an instance of the class anywhere else.

>> This link shows you how to separate the template class definition from its implementation
But, that isn't what the asker is trying to do. He wants to forward declare an object instance of the class not the class itself.

>> In your case, your .cpp file should include
That is forward declaring the class not an instance of the class. You won't be able to create an instance of the class unless the full template specification is visible at the POI.

>> then normally, we do not instantiate the class Foo in these two files
Which is why I said, "Not sure why you would want to do this" :)

>> This applies naturally to your template case as well
Well yes, except it's more complicated with templates because you have to understand the difference between POD (Point of Declaration) and POI (Point of Instantiation) and what the implications of this are in terms of what visibility the compiler needs at each of these two points.

Class templates do not behave like concrete templates when it comes to creating instances. The compiler MUST have visibility of the template definition at the point the instance is created, otherwise you will have linking errors. Basically, templates do not have external linkage.
0
phoffricCommented:
If I have time this weekend, I'll work up a C++03 example which may clarify my points.
0
sarabandeCommented:
The compiler MUST have full visibility of ALL the template code before the POI.
that isn't quite true. it only needs the template code that was "used" in the current source.

this allows you to put all internal code that was not used (called) from external code into a cpp file.

for example you could declare all functions to load data from a database into a template container and do a proper initialization without implementing them in the header. all implementation can go into a cpp file where you may instantiate the types needed or use internal template functions implemented in the same cpp file. you invoke the internal functions by using a non-template class/function.

// tree.h
...
template <typename T>
class Tree  : public BaseTree  // base class can be used for virtual calls
{
      SomeContainer sc;
      static int DBID;
public:
      // functions not exposed
      bool Load();
      bool Save();
      ...
public:
      // functions exposed
      Tree<T>() : BaseTree(Tree<T>::DBID) { sc.SetParent(this); }
      static Tree<T> & Instance() { static Tree<T> theTree; return theTree; }
      bool AddItem(T t, TreeHandle parent, TreeHandle prev) { sc.Add(t, parent, prev); }
      TreeHandle FindItem(T t) { return sc.Find(t); }
      ...
};

// tree.cpp
#include "tree.h"

// instantiate Trees and provide static members
// that also could be moved to any other cpp file
int Tree<Category>::DBID = 123;
int Tree<Location>::DBID = 456;

// assume TreeManager to be a singleton class
void TreeManager::LoadAllTrees()
{
     Tree<Category> & treecat = Tree<Category>::Instance();
     treecat.Load();
    Tree<Locations> & treeloc = Tree<Locations>::Instance();
     treeloc.Load();
}

bool Tree<T>::Load()
{
     bool ret = false;
     OpenDB();
     ret = LoadData(Tree<T>::DBID);
     return ret;
}

bool Tree<T>::Save()
{
     ...

Open in new window


note, you also could have such a template class in a dll (shared library). the only exception is that the functions like TreeManager::LoadAllTrees and the Tree<T>::Instance function need to be exported from the dll for all used template types such that the static members of the Instance function were exported as well.

also note, in the above sample there was non-template container class used. of course all implementations of that class doesn't need to be inline.

Sara
0
evilrixSenior Software Engineer (Avast)Commented:
>> that isn't quite true. it only needs the template code that was "used" in the current source.
Yes, you can split the implementation if you like but it becomes very messy and unmanageable for all but simple projects. I would advise against this and stick to the one header/one implementation file idiom (that is included in the header)
0
sarabandeCommented:
I would advise against this and stick to the one header/one implementation file idiom
really? actually, i thought that headers with a lot of non-trivial inline code are mainly seen as bad coding? and that it was a disadvantage of template coding that you hardly could avoid this?

since the sample code is derived from real code in a big project where we have about 50 dll's and where the database layer, the application layer and the gui layer are strictly separated, it makes much sense to separate implemention for the database layer from the access functions used in the application layer.

we made the experience that small template headers with trivial implementation are much better readable than huge headers perhaps with ugly coding and poor names like you could see in typical stl implementations. but surely, providing a container class for general use may focus on other criteria.

ClassTemplate<int> myObj; //I do not want to call the default constructor here

A.cpp
myObj(3);  //I want to instantiate it here and use a non-default constructor, one that take an int as its parameter

you can do the above by specialized constructors as already mentioned by evilrix.

template <typename T>
class ClassTemplate
{
        SomeType some_member;
        ...
public:
       ClassTemplate() {}   //does nothing
       ClassTemplate(int);  // only declaration
        ... 
};

// A.cpp
#include "classtemplate.h"
...

template <class T>
ClassTemplate<T>::ClassTemplate(int n) 
{
    some_member = n;
}

void f()
{
     ClassTemplate<int> x = 3;  // uses specialized constructor from above

     ClassTemplate<int> y;  // use default constructor with any type (even with int) as well
} 

Open in new window


note, you have to provide a default constructor for your case since a class which has only constructors where arguments are required, cannot be instantiated without arguments. the compiler would not add a default constructor then.

Sara
0
evilrixSenior Software Engineer (Avast)Commented:
>> really?
Yes.

>> i thought that headers with a lot of non-trivial inline code are mainly seen as bad coding? and that it was a disadvantage of template coding

But template functions are not inline, they are not even code as such; they don't exist until they are used, which is the POI (Point of Instantiation). If you only ever plan to use template code in a single translation unit you *can* define it in that single place, but if you want to use the template in multiple translation units you have no choice but to define the implementation in a file that needs to be included before the POI in each translation unit. You could put this into multiple implementation files, but their is little point because template code that is not instantiated doesn't contribute to the size of the compiled translation unit.

>> than huge headers perhaps with ugly coding
Did you see my example of separating the template class definition from the template class implementation using a "ipp" file? This is the generally accepted idiom (for example, it is how Boost does it).

Very few C++ programmers really understand templates at a compiler level, which is a shame because it often means they jump through hoops of fire completely unnecessarily. I'd strongly recommending getting hold of and reading "C++ Templates: The Complete Guide". Until you've read this you only think you know how C++ templates work!

http://www.amazon.co.uk/C-Templates-The-Complete-Guide/dp/0201734842
0
sarabandeCommented:
Did you see my example of separating the template class definition from the template class implementation using a "ipp" file?
yes. it happened to be my own approach when i began to create my first template containers. i used .cpp files though and included them at the bottom of the sources that were using the templates which was less elegant than to include them in the headers. to the times of c++ before stl, templates were not very well supported by existing c++ compilers. you had to use separate cpp files for to instantiate template code. otherwise some compilers used every type available in the source to compile the full template code what blows up the object files for nothing. then, multiple instantiations gave linker issues and more. in c i used void pointers and macros instead of templates what actually worked better as it sounds. we could port some simpler container templates from c++ to c that way with little changes.

Until you've read this you only think you know how C++ templates work!
oh. i am doing very much with templates. so i think i have at least an idea how they work (and currently have not so much time to read books). nevertheless, for specialized template containers it makes sense to use specialized template code and put it into cpp files. as shown it could be made very clean and with minimal overhead.

Sara
0
LuckyLucksAuthor Commented:
@evilrix

I get an : illegal storage class error when I declare it with the "extern" suffix in the header class.
0
evilrixSenior Software Engineer (Avast)Commented:
LuckyLucks, which compiler are you using?
0
evilrixSenior Software Engineer (Avast)Commented:
Older compilers tend to be very fussy when it comes to template code. I tested this code with Visual Studio 2015 and a recent version of gcc, without issue.

https://ideone.com/Ijnhul
0
LuckyLucksAuthor Commented:
I am using visual studio 2008 C++ compiler. I can't upgrade that for compatibility at the moment to a newer version.
0
LuckyLucksAuthor Commented:
is there a way around it in case the "extern" template declaration does not work for VS 2008? How else can i go about declaring a template in the header but instantiating it in the cpp?
0
evilrixSenior Software Engineer (Avast)Commented:
>> I am using visual studio 2008 C++ compiler.
Well, that's your answer. It's a very old compiler and had terrible template support. In fact, up until 2013 all versions of Visual Studio had terrible template support. Basically, the problem is the compiler not the code.

>> is there a way around it in case the "extern" template declaration does not work for VS 2008?
Yeah, don't do it. Again, I'm not even sure I really see the use case.

>> How else can i go about declaring a template in the header but instantiating it in the cpp?
You are not declaring a template, you are declaring a template instance. I have a feeling that what you are doing isn't really what you want to be doing and that you are just confusing different terminologies.

If all you want to do is create an instance of the template and use it this is all you need...

///////////////////////////////////////////////////////////////////////////////
// ClassTemplate.hpp

#pragma once

#include <iostream>

template <typename T>
class ClassTemplate
{
public:
   ClassTemplate()
   {
      std::cout << "ClassTemplate constructor" << std::endl;
   }

   void Test() const
   {
      std::cout << "ClassTemplate Test" << std::endl;
   }
};

///////////////////////////////////////////////////////////////////////////////
// a.hpp

#pragma once

class A
{
   public:
      A(ClassTemplate<int> const & obj)
      {
         // use it
         obj.Test();
      }
};

///////////////////////////////////////////////////////////////////////////////
// a.cpp

#include "ClassTemplate.hpp"
#include "a.hpp"

int main( int argc, char ** argv )
{
   ClassTemplate<int> obj; // construct instance

   A a(obj); // construct A, which uses obj
}

///////////////////////////////////////////////////////////////////////////////

Open in new window


https://ideone.com/u5MeAO
0
sarabandeCommented:
actually i can't see any need for 'extern' keyword. as explained (earlier) by evilrix the 'extern' was a failed attempt to put tempate implementation to cpp files.

the visual studio 2008 had a good compiler beside of 64-bit support.

if you want to use specialized code for templates look at the sample code i posted above.

Sara
0
evilrixSenior Software Engineer (Avast)Commented:
>> beside of 64-bit support.
And template support :D
0
sarabandeCommented:
do you want to say that

template <typename T>
class ClassTemplate
{
        SomeType some_member;
        ...
public:
       ClassTemplate() {}   //does nothing
       ClassTemplate(int);  // only declaration
        ... 
};

// A.cpp
#include "classtemplate.h"
...

template <class T>
ClassTemplate<T>::ClassTemplate(int n) 
{
    some_member = n;
}

void f()
{
     ClassTemplate<int> x = 3;  // uses specialized constructor from above

     ClassTemplate<int> y;  // use default constructor with any type (even with int) as well
} 

Open in new window


doesn't work with vs2008 or do you only want to have the last comment?

note, the code above was tested with vs2010. but today i will show that  vs2008 has no problems with that code either.

Basically, the problem is the compiler not the code.
Again, I'm not even sure I really see the use case.
I have a feeling that what you are doing isn't really what you want to be doing
???

Sara
0
evilrixSenior Software Engineer (Avast)Commented:
>> doesn't work with vs2008 or do you only want to have the last comment?
Due to the nature of my work, I tend to write very complex meta template code (if you've ever used the Boost MPL then you'll know what I'm talking about) and my experience is that, before 2013, Visual Studio just couldn't hack it.

Also, chill - did you not see the smiley. I was just busting your chops! We're all friends here. :p
0
LuckyLucksAuthor Commented:
@phoffric

I think you are misunderstanding my problem.
I have a template class called ClassTemplate , already set up in ClassTemplate.h

In some other random class A.h, I want to declare the template only, not instantiate it. That's why extern was a good idea (but it won't work with my compiler)
0
LuckyLucksAuthor Commented:
>You are not declaring a template, you are declaring a template instance.  

Yes, that's correct. sorry about the sloppy use of terminology
0
LuckyLucksAuthor Commented:
@evilrix
With reference to comments in "Expert Comment 2015-08-13 at 16:33:24ID: 40928876",
I did not see you declare a template instance in the A.h header file.

You code is below:

///////////////////////////////////////////////////////////////////////////////
// a.hpp

#pragma once

class A
{
   public:
      A(ClassTemplate<int> const & obj)
      {
         // use it
         obj.Test();
      }
};

///////////////////////////////////////////////////////////////////////////////



I need only one copy/instance of the template class ClassTemplate that I will manipulate in several methods of A.cpp. That's why I need that instance declared in A.h . This is very similar to any ordinary task where one declares an object of type B  (as B b;) in A.h and then instantiates and (b=new B();) in A.cpp
0
evilrixSenior Software Engineer (Avast)Commented:
>This is very similar to any ordinary task where one declares an object of type B  (as B b;) in A.h and then instantiates and (b=new B();) in A.cpp

You're refering to a global object, right? The answer is simple, don't use global variables, they are evil.

http://c2.com/cgi/wiki?GlobalVariablesAreBad
0
evilrixSenior Software Engineer (Avast)Commented:
If you require a single instance of myObj considet using the singleton pattern.

https://en.m.wikipedia.org/wiki/Singleton_pattern
0
LuckyLucksAuthor Commented:
no, not global variables.

A class,A, can declare member variables that are objects of  a type B, where B is another class.

I am trying to do the same thing here. Except B (or ClassTemplate) is not just another class, it is a template class.
0
evilrixSenior Software Engineer (Avast)Commented:
Right, well that is very different from what your question asker. Your question show you trying to declare an instance of a class, what you've just said in your last comment is that you want to forward declare a class type. When you forward declare a class you can only create pointers or references of that type, you can't create concrete types since the compiler will not know the size of the type to create. This is true for normal classes as well as template classes.

template <typename T>
class B;

class A
{
   B<int> * pInt; // this is allowed
   //B<int> & rObj; // this is allowed (although it must be intialied in c_tor)
   //B<int> obj; // this is not allowed as is it an incomplete type
};

template <typename T>
class B
{
};

int main()
{
   A a;
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
evilrixSenior Software Engineer (Avast)Commented:
>> do you want to say that...
No, I don't think I ever said that. Full specialisations can be defined in the .cpp file because they are concrete instances of a class and so do have linkage. Actual templates do NOT have linkage and so MUST be visible to the compiler at the Point of Instantiation. I'm not sure how much clearer I can make this!

Try this, it will not work on any compiler, not just 2008.

//////////////////////////////////////////////////////////////////////////////
// ClassTemplate.hpp

#pragma once

template <typename T>
class ClassTemplate
{
public:
       ClassTemplate();
};

//////////////////////////////////////////////////////////////////////////////
// a.cpp

#include "ClassTemplate.hpp"

// this is allowed but can not be used in another other translation unit
template <class T>
ClassTemplate<T>::ClassTemplate() 
{
}

void f()
{
     ClassTemplate<int> y; // fine
}

//////////////////////////////////////////////////////////////////////////////
// b.cpp

#include "ClassTemplate.hpp"

void f()
{
     ClassTemplate<int> y; // ERROR
} 

//////////////////////////////////////////////////////////////////////////////

Open in new window

0
sarabandeCommented:
i tried with vs2008:

// "testtemplate.h"
#pragma once

template <typename T>
class ClassTemplate
{
        double some_member;
public:
       ClassTemplate() {}   //does nothing
       ClassTemplate(int);  // only declaration
};

Open in new window


// "testtemplate.cpp" 
// note, it is 'not using precompiled header'
// or you have to include "stdafx.h" at top

#include "testtemplate.h"

template <class T>
ClassTemplate<T>::ClassTemplate(int n) 
{
    some_member = n;
}

void f()
{
     ClassTemplate<int> x = 3;  // uses specialized constructor from above

     ClassTemplate<int> y;  // use default constructor with any type (even with int) as well
} 

Open in new window


f can be called from everywhere in your program if you declare it in a header or on the fly like:

// testdlg.cpp
#include "stdafx.h"

....

void f();

void CMyTestDlgDlg::SomeMemberFunction()
{
     ...
     f();

Open in new window


the compiler isn't bad from my experiences. it was a good stable release especially compared to earlier releases of visual c++ .net coming with vs2002, vs2003, and vs2005.

Also, chill - did you not see the smiley. I was just busting your chops! We're all friends here. :p

:-)

Try this, it will not work on any compiler, not just 2008.
oh. may i also post any code sample which does not compile on any compiler? or only the template samples? how many posts were allowed to a thread? :D

Sara
0
evilrixSenior Software Engineer (Avast)Commented:
>> f can be called from everywhere in your program if you declare it in a header or on the fly like:
Yes, and that is exactly what I'd expect and I don't think I ever said otherwise. My assertion regarding 2008 wasn't for trivial template code like this. If it couldn't even to this that would be a problem. My assertion is regarding more complex meta-template code that should work on a standards compliant compiler but doesn't on older versions of Visual Studio because they did not implement the standard properly when it comes to templates. I don't have 2008 so I can't create you an example that demonstrates my point, so you can either take my work for it you we can just agree to disagree.

>> oh. may i also post any code sample which does not compile on any compiler?
But, the point is that is what I was talking about when I said you have to have the full template definition available at the POI. I posted that as an example so there was no ambiguity between my assertion and what you thought I meant :)

Anyway, like I said - we're all friends here and we really don't have to spend the whole thread trying to prove each other wrong. I'd much rather work with you than against you. You're a good C++ engineer, whose skills I respect so how about we join forces in battling the dark side?
0
sarabandeCommented:
Allez!

Sara
0
phoffricCommented:
You are right - I misunderstood your needs as shown in your OP.

Given your environment, I encourage you to include as one of your tags, "VS 2008". Also, if you post a small code snippet of your attempt that fails (with the compiler error), then we can determine quickly whether the problem is with your C++ code or with the VS 2008 compiler.

Now that there is long discussion with two apt experts, I know you are in good hands.
0
LuckyLucksAuthor Commented:
>Right, well that is very different from what your question asker.

Actually, my question asked exactly what i wanted to ask:
A.h  
ClassTemplate<int> myObj;  //declaring a template instance but not instantiating it

A.cpp
myObj(3);  //instantiating a template instance already declared in the header

Note: A is a class different from the template class, ClassTemplate.
0
phoffricCommented:
I think you are misunderstanding my problem.
 I have a template class called ClassTemplate , already set up in ClassTemplate.h

 In some other random class A.h, I want to declare the template only, not instantiate it.
Now that I understand your problem better, here is the output of a little program shown below:
ClassTemplate ctor here
A ctor
foo here: A_Val = 3

Open in new window

// ClassTemplate.hpp
#ifndef CLASSTEMPLATE_HPP
#define CLASSTEMPLATE_HPP

#include <iostream>

template <class T>
class ClassTemplate
{
public:
   ClassTemplate(T aval) : A_Val(aval)
   {
      std::cout << "ClassTemplate ctor here" << std::endl;
   }

   void foo() 
   {
      std::cout << "foo here: A_Val = " << A_Val << std::endl;
   }
private:
   T A_Val;
};

#endif

Open in new window

// a.hpp
#ifndef A_HPP
#define A_HPP

#include "ClassTemplate.hpp"
#include <iostream>

class A
{
public:
   A();

   void Test()
   {
      myObj.foo();
   }

private:
   ClassTemplate<int> myObj;   // declare the template class member only; do not instantiate it.
};

#endif

Open in new window

// a.cpp
#include "a.hpp"
#include "ClassTemplate.hpp"

A::A() : myObj(3)     // instantiating myObj in A's constructor
{ 
   std::cout << "A ctor" << std::endl;
}

int main()
{
   A hello;
   hello.Test();
}

Open in new window

0
LuckyLucksAuthor Commented:
Since I cannot use forward declaration in vs2008,  a pointer approach will work for me. thanks evilrix.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual C++.NET

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.